From 41e2f7da6259c79b6164af2e13f903224bdb5078 Mon Sep 17 00:00:00 2001 From: Philipp Kramer Date: Tue, 26 Nov 2019 15:03:54 +0100 Subject: [PATCH] import zed package --- Assets/Scenes/SampleScene.unity | 187 +- Assets/ZED.meta | 9 + Assets/ZED/Doc.meta | 9 + Assets/ZED/Doc/ReleaseNotes.md | 305 ++ Assets/ZED/Doc/ReleaseNotes.md.meta | 8 + Assets/ZED/Editor.meta | 9 + Assets/ZED/Editor/Scripts.meta | 9 + Assets/ZED/Editor/Scripts/BuildScript.cs | 8 + Assets/ZED/Editor/Scripts/BuildScript.cs.meta | 12 + Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs | 1063 +++++++ .../Editor/Scripts/ZEDCameraEditor.cs.meta | 12 + .../ZED/Editor/Scripts/ZEDPluginInspector.cs | 573 ++++ .../Editor/Scripts/ZEDPluginInspector.cs.meta | 12 + Assets/ZED/Prefabs.meta | 9 + Assets/ZED/Prefabs/ZED_Rig_Mono.prefab | 293 ++ Assets/ZED/Prefabs/ZED_Rig_Mono.prefab.meta | 9 + Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab | 663 +++++ Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab.meta | 9 + Assets/ZED/SDK.meta | 9 + Assets/ZED/SDK/Helpers.meta | 9 + Assets/ZED/SDK/Helpers/Resources.meta | 9 + .../ZED/SDK/Helpers/Resources/Materials.meta | 9 + .../SDK/Helpers/Resources/Materials/GUI.meta | 9 + .../Resources/Materials/GUI/Mat_ZED_Fade.mat | 77 + .../Materials/GUI/Mat_ZED_Fade.mat.meta | 9 + .../Resources/Materials/GUI/Mat_ZED_UITop.mat | 83 + .../Materials/GUI/Mat_ZED_UITop.mat.meta | 9 + .../Helpers/Resources/Materials/Lighting.meta | 9 + .../Materials/Lighting/Mat_ZED_Deferred.mat | 40 + .../Lighting/Mat_ZED_Deferred.mat.meta | 9 + .../Lighting/Mat_ZED_Deferred_Lighting.mat | 88 + .../Mat_ZED_Deferred_Lighting.mat.meta | 9 + .../Materials/Lighting/Mat_ZED_Forward.mat | 44 + .../Lighting/Mat_ZED_Forward.mat.meta | 9 + .../Lighting/Mat_ZED_Forward_Lighting.mat | 94 + .../Mat_ZED_Forward_Lighting.mat.meta | 9 + .../Materials/Lighting/Mat_ZED_Hide.mat | 76 + .../Materials/Lighting/Mat_ZED_Hide.mat.meta | 9 + .../Resources/Materials/PlaneDetection.meta | 9 + .../Mat_ZED_Geometry_WirePlane.mat | 87 + .../Mat_ZED_Geometry_WirePlane.mat.meta | 9 + .../Resources/Materials/PointCloud.meta | 9 + .../PointCloud/Mat_ZED_PointCloud.mat | 77 + .../PointCloud/Mat_ZED_PointCloud.mat.meta | 9 + .../Resources/Materials/PostProcessing.meta | 9 + .../Materials/PostProcessing/Mat_ZED_Blit.mat | 76 + .../PostProcessing/Mat_ZED_Blit.mat.meta | 9 + .../Materials/PostProcessing/Mat_ZED_Blur.mat | 76 + .../PostProcessing/Mat_ZED_Blur.mat.meta | 9 + .../PostProcessing/Mat_ZED_MaskCompositor.mat | 76 + .../Mat_ZED_MaskCompositor.mat.meta | 9 + .../PostProcessing/Mat_ZED_PostProcessing.mat | 77 + .../Mat_ZED_PostProcessing.mat.meta | 9 + .../PostProcessing/Mat_ZED_Stencil2Mask.mat | 76 + .../Mat_ZED_Stencil2Mask.mat.meta | 9 + .../Mat_ZED_Surface_PostProcessing.mat | 76 + .../Mat_ZED_Surface_PostProcessing.mat.meta | 9 + .../Mat_ZED_Unlit_PostProcessing.mat | 76 + .../Mat_ZED_Unlit_PostProcessing.mat.meta | 9 + .../Resources/Materials/SpatialMapping.meta | 9 + .../Mat_ZED_Geometry_Wireframe.mat | 87 + .../Mat_ZED_Geometry_Wireframe.mat.meta | 9 + .../Mat_ZED_PostProcess_Blend.mat | 77 + .../Mat_ZED_PostProcess_Blend.mat.meta | 9 + .../SpatialMapping/Mat_ZED_Texture.mat | 76 + .../SpatialMapping/Mat_ZED_Texture.mat.meta | 9 + .../Mat_ZED_Wireframe_Video_Overlay.mat | 77 + .../Mat_ZED_Wireframe_Video_Overlay.mat.meta | 7 + .../Helpers/Resources/Materials/Unlit.meta | 9 + .../Materials/Unlit/Mat_ZED_Unlit.mat | 76 + .../Materials/Unlit/Mat_ZED_Unlit.mat.meta | 9 + .../Materials/Unlit/Mat_ZED_Unlit_BGRA.mat | 82 + .../Unlit/Mat_ZED_Unlit_BGRA.mat.meta | 9 + .../ZED/SDK/Helpers/Resources/PrefabsUI.meta | 9 + .../Resources/PrefabsUI/Animation.meta | 9 + .../PrefabsUI/Animation/Loading.anim | 119 + .../PrefabsUI/Animation/Loading.anim.meta | 9 + .../Helpers/Resources/PrefabsUI/Material.meta | 9 + .../PrefabsUI/Material/GUIOverlay.mat | 83 + .../PrefabsUI/Material/GUIOverlay.mat.meta | 9 + .../PrefabsUI/Material/GUIOverlayCustom.mat | 82 + .../Material/GUIOverlayCustom.mat.meta | 9 + .../PrefabsUI/Material/GUIOverlayText.mat | 83 + .../Material/GUIOverlayText.mat.meta | 9 + .../Helpers/Resources/PrefabsUI/Shader.meta | 9 + .../PrefabsUI/Shader/OverlayCustom.shader | 99 + .../Shader/OverlayCustom.shader.meta | 9 + .../Helpers/Resources/PrefabsUI/Textures.meta | 9 + .../Resources/PrefabsUI/Textures/Loading.meta | 9 + .../Textures/Loading/HelveticaNeue Medium.ttf | Bin 0 -> 39656 bytes .../Loading/HelveticaNeue Medium.ttf.meta | 21 + .../PrefabsUI/Textures/Loading/Loading.anim | 170 ++ .../Textures/Loading/Loading.anim.meta | 9 + .../Textures/Loading/LoadingSprite.png | Bin 0 -> 9022383 bytes .../Textures/Loading/LoadingSprite.png.meta | 943 +++++++ .../Textures/Loading/Spinner 1.controller | 67 + .../Loading/Spinner 1.controller.meta | 9 + .../Textures/Loading/backgroundloading.png | Bin 0 -> 2840 bytes .../Loading/backgroundloading.png.meta | 103 + .../Resources/PrefabsUI/Warning.prefab | 361 +++ .../Resources/PrefabsUI/Warning.prefab.meta | 9 + .../Resources/PrefabsUI/Warning_VR.prefab | 361 +++ .../PrefabsUI/Warning_VR.prefab.meta | 9 + Assets/ZED/SDK/Helpers/Scripts.meta | 9 + Assets/ZED/SDK/Helpers/Scripts/Display.meta | 9 + .../Scripts/Display/HideFromWrongCameras.cs | 120 + .../Display/HideFromWrongCameras.cs.meta | 12 + .../Scripts/Display/ZEDPointCloudManager.cs | 243 ++ .../Display/ZEDPointCloudManager.cs.meta | 12 + .../Scripts/Display/ZEDPostProcessingTools.cs | 242 ++ .../Display/ZEDPostProcessingTools.cs.meta | 12 + .../Scripts/Display/ZEDRenderingPlane.cs | 1475 ++++++++++ .../Scripts/Display/ZEDRenderingPlane.cs.meta | 12 + .../ZED/SDK/Helpers/Scripts/Interactions.meta | 9 + .../Interactions/ZEDControllerManager.cs | 97 + .../Interactions/ZEDControllerManager.cs.meta | 12 + .../Interactions/ZEDControllerTracker.cs | 740 +++++ .../Interactions/ZEDControllerTracker.cs.meta | 12 + .../ZEDControllerTracker_DemoInputs.cs | 506 ++++ .../ZEDControllerTracker_DemoInputs.cs.meta | 12 + .../Interactions/ZEDOffsetController.cs | 303 ++ .../Interactions/ZEDOffsetController.cs.meta | 12 + .../Interactions/ZEDTransformController.cs | 352 +++ .../ZEDTransformController.cs.meta | 12 + Assets/ZED/SDK/Helpers/Scripts/Lighting.meta | 9 + .../SDK/Helpers/Scripts/Lighting/ZEDLight.cs | 70 + .../Helpers/Scripts/Lighting/ZEDLight.cs.meta | 12 + Assets/ZED/SDK/Helpers/Scripts/MR.meta | 9 + .../ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs | 46 + .../SDK/Helpers/Scripts/MR/ZEDMirror.cs.meta | 12 + .../Scripts/MR/ZEDMixedRealityPlugin.cs | 867 ++++++ .../Scripts/MR/ZEDMixedRealityPlugin.cs.meta | 12 + .../SDK/Helpers/Scripts/PlaneDetection.meta | 9 + .../ZEDPlaneDetectionManager.cs | 665 +++++ .../ZEDPlaneDetectionManager.cs.meta | 12 + .../PlaneDetection/ZEDPlaneGameObject.cs | 465 ++++ .../PlaneDetection/ZEDPlaneGameObject.cs.meta | 12 + .../SDK/Helpers/Scripts/SpatialMapping.meta | 9 + .../Scripts/SpatialMapping/ZEDMeshRenderer.cs | 143 + .../SpatialMapping/ZEDMeshRenderer.cs.meta | 12 + .../SpatialMapping/ZEDSpatialMapping.cs | 1643 +++++++++++ .../SpatialMapping/ZEDSpatialMapping.cs.meta | 12 + Assets/ZED/SDK/Helpers/Scripts/Utilities.meta | 9 + .../Helpers/Scripts/Utilities/CappedStack.cs | 40 + .../Scripts/Utilities/CappedStack.cs.meta | 11 + .../Helpers/Scripts/Utilities/GUIMessage.cs | 398 +++ .../Scripts/Utilities/GUIMessage.cs.meta | 12 + .../Helpers/Scripts/Utilities/LayerHandler.cs | 153 + .../Scripts/Utilities/LayerHandler.cs.meta | 12 + .../Helpers/Scripts/Utilities/LoadingFade.cs | 79 + .../Scripts/Utilities/LoadingFade.cs.meta | 12 + .../SDK/Helpers/Scripts/Utilities/Utils.cs | 102 + .../Helpers/Scripts/Utilities/Utils.cs.meta | 12 + .../Scripts/Utilities/ZEDLogMessage.cs | 203 ++ .../Scripts/Utilities/ZEDLogMessage.cs.meta | 12 + .../Scripts/Utilities/ZEDSVOManager.cs | 346 +++ .../Scripts/Utilities/ZEDSVOManager.cs.meta | 12 + .../Scripts/Utilities/ZEDSupportFunctions.cs | 634 +++++ .../Utilities/ZEDSupportFunctions.cs.meta | 12 + Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs | 2401 ++++++++++++++++ .../SDK/Helpers/Scripts/ZEDManager.cs.meta | 12 + Assets/ZED/SDK/Helpers/Shaders.meta | 9 + Assets/ZED/SDK/Helpers/Shaders/GUI.meta | 9 + .../GUI/ZED_Default_OverlayNoZTest.shader | 93 + .../ZED_Default_OverlayNoZTest.shader.meta | 9 + .../SDK/Helpers/Shaders/GUI/ZED_Fade.shader | 59 + .../Helpers/Shaders/GUI/ZED_Fade.shader.meta | 9 + Assets/ZED/SDK/Helpers/Shaders/Lighting.meta | 9 + .../Shaders/Lighting/ZED_Deferred.shader | 153 + .../Shaders/Lighting/ZED_Deferred.shader.meta | 9 + .../Lighting/ZED_Deferred_Lighting.shader | 174 ++ .../ZED_Deferred_Lighting.shader.meta | 9 + .../Shaders/Lighting/ZED_Forward.shader | 111 + .../Shaders/Lighting/ZED_Forward.shader.meta | 9 + .../Lighting/ZED_Forward_Lighting.shader | 153 + .../Lighting/ZED_Forward_Lighting.shader.meta | 9 + .../Helpers/Shaders/Lighting/ZED_Hide.shader | 54 + .../Shaders/Lighting/ZED_Hide.shader.meta | 9 + .../Shaders/Lighting/ZED_Lighting.cginc | 164 ++ .../Shaders/Lighting/ZED_Lighting.cginc.meta | 9 + .../SDK/Helpers/Shaders/PlaneDetection.meta | 9 + .../PlaneDetection/GeometryWirePlane.shader | 121 + .../GeometryWirePlane.shader.meta | 9 + .../SDK/Helpers/Shaders/PostProcessing.meta | 9 + .../Shaders/PostProcessing/ZED_Blit.shader | 55 + .../PostProcessing/ZED_Blit.shader.meta | 9 + .../Shaders/PostProcessing/ZED_Blur.shader | 301 ++ .../PostProcessing/ZED_Blur.shader.meta | 9 + .../PostProcessing/ZED_ComposeMask.shader | 54 + .../ZED_ComposeMask.shader.meta | 9 + .../PostProcessing/ZED_Post-Processing.shader | 105 + .../ZED_Post-Processing.shader.meta | 9 + .../PostProcessing/ZED_StencilToMask.shader | 54 + .../ZED_StencilToMask.shader.meta | 9 + .../ZED_Surface_PostProcessing.shader | 58 + .../ZED_Surface_PostProcessing.shader.meta | 9 + .../ZED_Unlit_PostProcessing.shader | 68 + .../ZED_Unlit_PostProcessing.shader.meta | 9 + .../SDK/Helpers/Shaders/SpatialMapping.meta | 9 + .../SpatialMapping/GeometryWireframe.shader | 120 + .../GeometryWireframe.shader.meta | 7 + .../SpatialMapping/Postprocess_blend.shader | 80 + .../Postprocess_blend.shader.meta | 9 + .../Shaders/SpatialMapping/Textures.shader | 53 + .../SpatialMapping/Textures.shader.meta | 9 + .../WireframeVideoOverlay.shader | 65 + .../WireframeVideoOverlay.shader.meta | 9 + Assets/ZED/SDK/Helpers/Shaders/Unlit.meta | 9 + .../Helpers/Shaders/Unlit/ZED_Unlit.shader | 52 + .../Shaders/Unlit/ZED_Unlit.shader.meta | 9 + .../SDK/Helpers/Shaders/ZED_PointCloud.shader | 82 + .../Shaders/ZED_PointCloud.shader.meta | 9 + .../ZED/SDK/Helpers/Shaders/ZED_Utils.cginc | 121 + .../SDK/Helpers/Shaders/ZED_Utils.cginc.meta | 9 + Assets/ZED/SDK/NativeInterface.meta | 9 + Assets/ZED/SDK/NativeInterface/ZEDCamera.cs | 2459 +++++++++++++++++ .../ZED/SDK/NativeInterface/ZEDCamera.cs.meta | 12 + .../SDK/NativeInterface/ZEDCameraSettings.cs | 414 +++ .../NativeInterface/ZEDCameraSettings.cs.meta | 12 + Assets/ZED/SDK/NativeInterface/ZEDCommon.cs | 1185 ++++++++ .../ZED/SDK/NativeInterface/ZEDCommon.cs.meta | 12 + Assets/ZED/SDK/NativeInterface/ZEDMat.cs | 875 ++++++ Assets/ZED/SDK/NativeInterface/ZEDMat.cs.meta | 12 + Assets/ZED/SDK/Plugins.meta | 9 + .../SDK/Plugins/SteamVR_ZED_Unity_Plugin.meta | 8 + .../Plugins/SteamVR_ZED_Unity_Plugin/29.meta | 9 + .../SteamVR_ZED_Unity_Plugin/29/actions.json | 58 + .../29/actions.json.meta | 7 + .../29/steamvr_partial_manifest.json | 7 + .../29/steamvr_partial_manifest.json.meta | 7 + Assets/ZED/SDK/Plugins/win64.meta | 8 + .../ZED/SDK/Plugins/win64/sl_unitywrapper.dll | Bin 0 -> 379392 bytes .../Plugins/win64/sl_unitywrapper.dll.meta | 27 + Assets/ZED/SDK/Shaders.meta | 9 + Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader | 54 + .../SDK/Shaders/ZED_Unlit_BGRA.shader.meta | 9 + ProjectSettings/ProjectSettings.asset | 9 +- ProjectSettings/QualitySettings.asset | 14 +- ProjectSettings/TagManager.asset | 3 +- 239 files changed, 28245 insertions(+), 100 deletions(-) create mode 100644 Assets/ZED.meta create mode 100644 Assets/ZED/Doc.meta create mode 100644 Assets/ZED/Doc/ReleaseNotes.md create mode 100644 Assets/ZED/Doc/ReleaseNotes.md.meta create mode 100644 Assets/ZED/Editor.meta create mode 100644 Assets/ZED/Editor/Scripts.meta create mode 100644 Assets/ZED/Editor/Scripts/BuildScript.cs create mode 100644 Assets/ZED/Editor/Scripts/BuildScript.cs.meta create mode 100644 Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs create mode 100644 Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs.meta create mode 100644 Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs create mode 100644 Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs.meta create mode 100644 Assets/ZED/Prefabs.meta create mode 100644 Assets/ZED/Prefabs/ZED_Rig_Mono.prefab create mode 100644 Assets/ZED/Prefabs/ZED_Rig_Mono.prefab.meta create mode 100644 Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab create mode 100644 Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab.meta create mode 100644 Assets/ZED/SDK.meta create mode 100644 Assets/ZED/SDK/Helpers.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/GUI.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_Fade.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_Fade.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_UITop.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_UITop.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred_Lighting.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred_Lighting.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward_Lighting.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward_Lighting.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Hide.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Hide.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud/Mat_ZED_PointCloud.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud/Mat_ZED_PointCloud.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blit.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blit.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blur.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blur.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_MaskCompositor.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_MaskCompositor.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_PostProcessing.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_PostProcessing.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Stencil2Mask.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Stencil2Mask.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Surface_PostProcessing.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Surface_PostProcessing.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Unlit_PostProcessing.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Unlit_PostProcessing.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_PostProcess_Blend.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_PostProcess_Blend.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Texture.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Texture.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Unlit.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit_BGRA.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit_BGRA.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation/Loading.anim create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation/Loading.anim.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlay.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlay.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayCustom.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayCustom.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayText.mat create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayText.mat.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader/OverlayCustom.shader create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader/OverlayCustom.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/HelveticaNeue Medium.ttf create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/HelveticaNeue Medium.ttf.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Loading.anim create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Loading.anim.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/LoadingSprite.png create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/LoadingSprite.png.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Spinner 1.controller create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Spinner 1.controller.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/backgroundloading.png create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/backgroundloading.png.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning.prefab create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning.prefab.meta create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning_VR.prefab create mode 100644 Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning_VR.prefab.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display/HideFromWrongCameras.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display/HideFromWrongCameras.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker_DemoInputs.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker_DemoInputs.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Lighting.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/MR.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/PlaneDetection.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/SpatialMapping.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/CappedStack.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/CappedStack.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/LayerHandler.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/LayerHandler.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs create mode 100644 Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/GUI.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Default_OverlayNoZTest.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Default_OverlayNoZTest.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Fade.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Fade.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred_Lighting.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred_Lighting.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward_Lighting.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward_Lighting.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Hide.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Hide.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Lighting.cginc create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Lighting.cginc.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PlaneDetection.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PlaneDetection/GeometryWirePlane.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PlaneDetection/GeometryWirePlane.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blit.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blit.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blur.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blur.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_ComposeMask.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_ComposeMask.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Post-Processing.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Post-Processing.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_StencilToMask.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_StencilToMask.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Surface_PostProcessing.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Surface_PostProcessing.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Unlit_PostProcessing.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Unlit_PostProcessing.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/GeometryWireframe.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/GeometryWireframe.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Postprocess_blend.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Postprocess_blend.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Textures.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Textures.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/WireframeVideoOverlay.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/WireframeVideoOverlay.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Unlit.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Unlit/ZED_Unlit.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/Unlit/ZED_Unlit.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/ZED_PointCloud.shader create mode 100644 Assets/ZED/SDK/Helpers/Shaders/ZED_PointCloud.shader.meta create mode 100644 Assets/ZED/SDK/Helpers/Shaders/ZED_Utils.cginc create mode 100644 Assets/ZED/SDK/Helpers/Shaders/ZED_Utils.cginc.meta create mode 100644 Assets/ZED/SDK/NativeInterface.meta create mode 100644 Assets/ZED/SDK/NativeInterface/ZEDCamera.cs create mode 100644 Assets/ZED/SDK/NativeInterface/ZEDCamera.cs.meta create mode 100644 Assets/ZED/SDK/NativeInterface/ZEDCameraSettings.cs create mode 100644 Assets/ZED/SDK/NativeInterface/ZEDCameraSettings.cs.meta create mode 100644 Assets/ZED/SDK/NativeInterface/ZEDCommon.cs create mode 100644 Assets/ZED/SDK/NativeInterface/ZEDCommon.cs.meta create mode 100644 Assets/ZED/SDK/NativeInterface/ZEDMat.cs create mode 100644 Assets/ZED/SDK/NativeInterface/ZEDMat.cs.meta create mode 100644 Assets/ZED/SDK/Plugins.meta create mode 100644 Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin.meta create mode 100644 Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29.meta create mode 100644 Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/actions.json create mode 100644 Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/actions.json.meta create mode 100644 Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/steamvr_partial_manifest.json create mode 100644 Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/steamvr_partial_manifest.json.meta create mode 100644 Assets/ZED/SDK/Plugins/win64.meta create mode 100644 Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll create mode 100644 Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll.meta create mode 100644 Assets/ZED/SDK/Shaders.meta create mode 100644 Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader create mode 100644 Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader.meta diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 43607ab..2a05e8a 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 705507994} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -50,12 +50,11 @@ LightmapSettings: m_BounceScale: 1 m_IndirectOutputScale: 1 m_AlbedoBoost: 1 - m_TemporalCoherenceThreshold: 1 m_EnvironmentLightingMode: 0 m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 0 m_LightmapEditorSettings: - serializedVersion: 10 + serializedVersion: 12 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 @@ -63,6 +62,7 @@ LightmapSettings: m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 @@ -77,10 +77,16 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 - m_PVRFilteringMode: 1 + m_PVREnvironmentMIS: 0 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 @@ -88,7 +94,8 @@ LightmapSettings: m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ShowResolutionOverlay: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData m_LightingDataAsset: {fileID: 0} m_UseShadowmask: 1 --- !u!196 &4 @@ -117,7 +124,8 @@ NavMeshSettings: GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - component: {fileID: 705507995} @@ -133,15 +141,17 @@ GameObject: Light: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 705507993} m_Enabled: 1 - serializedVersion: 8 + serializedVersion: 9 m_Type: 1 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 m_CookieSize: 10 m_Shadows: m_Type: 2 @@ -151,6 +161,24 @@ Light: m_Bias: 0.05 m_NormalBias: 0.4 m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 m_Cookie: {fileID: 0} m_DrawHalo: 0 m_Flare: {fileID: 0} @@ -158,102 +186,85 @@ Light: m_CullingMask: serializedVersion: 2 m_Bits: 4294967295 + m_RenderingLayerMask: 1 m_Lightmapping: 1 m_LightShadowCasterMode: 0 m_AreaSize: {x: 1, y: 1} m_BounceIntensity: 1 m_ColorTemperature: 6570 m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 m_ShadowRadius: 0 m_ShadowAngle: 0 --- !u!4 &705507995 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 705507993} m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalPosition: {x: 0, y: 3, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!1 &963194225 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 963194228} - - component: {fileID: 963194227} - - component: {fileID: 963194226} - m_Layer: 0 - m_Name: Main Camera - m_TagString: MainCamera - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!81 &963194226 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 963194225} - m_Enabled: 1 ---- !u!20 &963194227 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 963194225} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} - m_projectionMatrixMode: 1 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - m_GateFitMode: 2 - m_FocalLength: 50 - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: -1 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &963194228 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 963194225} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1001 &2018767638 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 1603769914748404, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_Name + value: ZED_Rig_Stereo + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_RootOrder + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4309805032874704, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: e13ee7e0790c7d243b7aa67fe604acac, type: 3} diff --git a/Assets/ZED.meta b/Assets/ZED.meta new file mode 100644 index 0000000..bf2420a --- /dev/null +++ b/Assets/ZED.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bbdb1ce4d5870ea43aa02a952da72f95 +folderAsset: yes +timeCreated: 1488815750 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Doc.meta b/Assets/ZED/Doc.meta new file mode 100644 index 0000000..eda1ac3 --- /dev/null +++ b/Assets/ZED/Doc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ff0926a8284869f4aa937bbf2c888adc +folderAsset: yes +timeCreated: 1543443410 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Doc/ReleaseNotes.md b/Assets/ZED/Doc/ReleaseNotes.md new file mode 100644 index 0000000..94dd4e4 --- /dev/null +++ b/Assets/ZED/Doc/ReleaseNotes.md @@ -0,0 +1,305 @@ + +### 2.8.0 + + * **Features**: + * Added Multi ZED Rig support: + - *Complete refactoring of the wrapper and plugin to change singleton implementation into multi instance support. The maximum number of instance is limited to 4 cameras.* + - *Each ZEDManager now has a ZED_CAMERA_ID to define its own camera ID.* + - *All static events in ZEDManager have been replaced by "local" events to make them specific to a rig/camera. Example: OnZEDReady* + - *Added ZEDManager.GetInstance(sl.ZED_CAMERA_ID) static function to access the ZEDManager in a external script without having the ZEDManager as a parameter of the script. Note that the user must check the return value of this function since it can be null.* + - *Added ZEDManager.GetInstances() to list all ZEDManagers in the scene.* + - *Spatial Mapping module and Camera settings module have been moved to ZEDManager to simplify their use in a multi or single ZED configuration.* + - *Added MultiCam example to show how to use 2 ZEDs in a single application.* + - *Overhauled many scripts to take advantage of multiple cameras when possible. For example, projectiles in the Drone Shooter sample can collide with the world seen by any camera.* + * Added Streaming module from ZED SDK 2.8: + - ***Input*** : *You can now receive a video stream from a ZED over the network, and process it locally. Do this by setting ZEDManager's Input Type to "Stream" in the Inspector, and specify the IP/Port configuration of the sender.* + - ***Output*** : *To broadcast a stream, set the ZED's Input Type to USB or SVO, and open the "Streaming" section further down. Specify the codec/streaming configuration if necessayr and check "Enable Streaming Output".* + - *You can adjust camera settings from a receiving PC, allowing you to control an entire scene from a single device.* + * Added initial camera position estimation option to ZEDManager: + - *If EnableTracking is activated, estimateInitialPosition will simply activate the TrackingParameters::set_floor_as_origin to estimate the floor position, and therefore the camera position, during tracking initialization. * + - *If EnableTracking is not used, estimateInitialPosition will try to detect the floor planes multiple times and compute an average camera position from the floor position.* + * Pose smoothing added to spatial memory feature, so pose corrections no longer appear as "jumps." + * Added manually turning the ZED's LED light on and off, to be used for debugging. See ZEDCameraSettings. + * Added option in ZEDManager's Advanced Settings to grey out the skybox when the scene starts. This was done automatically before to avoid affecting AR lighting, but can be disabled for greenscreen use. + + * **Improvements**: + * Removed ZED rigs' dependence on layers: + - Previously, the "frame" quads in each ZED rig (including the hidden AR rig) were assigned their own layer, and all other cameras had this layer removed from their culling mask. This made it so no camera would see a frame meant for another eye, but left fewer layers available to the user and made the cameras' culling masks impossible to set from the Inspector. + - Frames now use the HideFromWrongCamera script to prevent rendering to the wrong cameras without the use of layers. Cameras in ZED_Rig_Mono and ZED_Rig_Stereo can have their culling masks set freely. + - The hidden AR camera rig still uses a single "AR layer", customizable in ZEDManager's Advanced Settings, so that it can see the frame without seeing any other objects. This was done as an alternative to drawing the quad with Graphics.Draw, which would make it difficult for newer users to understand. + * Moved all SVO features from ZEDSVOManager (now deprecated) to ZEDManager: + - Read an existing SVO by setting Input Type to "SVO" and specifying a file. + - Record a new SVO by opening the "Recording" section. You now need to press "Start Recording" from the editor or call ZEDCamera.EnableRecording() in a script (and ZEDCamera.DisableRecording() to stop). + * Planes detected by the ZED no longer drawn with a hidden camera, allowing them to be drawn at the same time as a spatial mapping wireframe. + * ZEDPlaneDetectionManager can now have "Visible in Scene" disabled and "Visible in Scene" enabled at the same time. + + * **Bug Fixes**: + * Fixed bug that overwrites camera position if user set one before starting the scene (when tracking is not activated). + * Fixed latency compensation in ZEDControllerTracker causing the ZED to drift infinitely when a ZED rig was a child of it. + * Fixed normally-hidden AR rig not appearing in the Hierarchy on start if "Show Final AR Rig" was enabled before runtime. + * Fixed app taking a long time to close if closed while a ZED was still initializing. + * Fixed asteroids in Planetarium sample only being drawn to layer 8. + + + * **Compatibility**: + * Compatible with ZED SDK 2.8, CUDA 9.0 and 10.0. + * Updated controller scripts to work with the new SteamVR Unity plugin v2.0, so long as its Action system has not been activated. + +### 2.8.1 + + * **Improvements:** + + * * Updated ZEDControllerTracker: + - Added input support for SteamVR plugin 2.0 and greater + - Added ZEDControllerTracker_DemoInputs, which inherits from ZEDControllerTracker, but with generic button/axis check functions + - These functions work whether using SteamVR or Oculus Unity plugins + - Several scripts in Example scenes are now simplified to call these functions instead of having plugin-specific code. + * Removed limit on how long ZEDManager would attempt to connect to the ZED camera - previously 10 seconds + * ZEDTransformController, used to move object like the Planetarium and Movie Screen in example scenes, now takes into account the Reposition At Start feature added to ZEDManager in 2.8 + * Shader properties that are retrieved or modified more than once per scene now have their property IDs cached, saving lookups + * ZEDManager can now be used outside of the included prefabs, and is more flexible when determining if it's in "stereo" mode (like the ZED_Rig_Stereo prefab) for loading AR pass-through features. + * ZEDManager's process for closing cameras when the scene closes is now more stable + + * **Bug Fixes:** + + * Fixed ZEDControllerTracker's latency compensation feature moving the controller incorrectly when using ZED in third person + * Fixed non-rendering Camera objects not getting properly disposed at scene close, causing performance issues after running scene in editor repeatedly + * Camera Brightness adjustment now works in deferred rendering (Global Shader value) + * Fixed #ZED_OCULUS compiler directive not getting activated when newer Oculus package is imported + * Fixed newer Oculus package causing #ZED_STEAM_VR compiler directive getting activated when importing Oculus package. This would also happen when importing the OpenVR package in Unity 2019 + * Fixed ZEDControllerTracker not updating Oculus Touch controller position if only one controller is connected + * Fixed ZEDSupportFunctions.GetForwardDistanceAtPixel not properly accounting for screen size + * Fixed "ZED Disconnected" error message not being locked to the headset when using ZED_Rig_Stereo + * Fixed Planetarium example scene being way too dark in deferred rendering + * Fixed plugin not recognizing Dell VISOR or Lenovo Explorer WMR headsets when using them in SteamVR, or any WMR controllers at all. + * Updated video stream link in Movie Screen example scene as the old video link was taken down (same video, new host) + * Fixed SVO Loop feature not working when real-time mode is enabled + * Fixed Multicam crash if both cameras share the same CAMERA_ID + +### 2.8.2 + + * **Features:** + * Added OpenCV ArUco marker detection sample scene. If you've also imported the OpenCV for Unity package from the Asset Store, you can place objects in 3D where ArUco-stlye markers are detected. + * Added brand new Mixed Reality calibration app as a sample scene. You can now calibrate the ZED with a tracked object for mixed reality VR capture, all from within the Unity editor. + + * **Improvements:** + * Added Max Depth Range and Confidence Threshold options in ZEDManager's Advanced Settings + * Added option to disable IMU prior setting in ZEDManager's Advanced Settings + * Changed how meshes scanned with the Spatial Mapping feature were saved, to avoid them being flipped on the Z axis when re-imported + * Added option to set which side of the ZED (left or right) that ZEDRenderingPlane retrieves. This also solved an issue where the right camera in the ZED_Rig_Stereo prefab would display the left feed when not in AR pass-through mode + + * **Bug Fixes:** + * Fixed a crash that would happen if two ZEDManagers were set to use the same Camera ID + * Fixed ZED_Rig_Stereo sometimes not outputting an image to the Game window in newer versions of Unity + * Fixed ZED_GreenScreen prefab setting that caused the output to be displayed in only half the screen + * Fixed depth values being incorrect for occlusion when using OpenGL instead of DirectX + + + +### 2.7.0 + + * **Features**: + - Added toggle box to reveal a camera rig used for final HMD output, normally hidden, for advanced users + - Added toggle boxes for the fade-in effect when the ZED initializes, and setting the ZED rig Gameobject to "DontDestroyOnLoad" on start + + + * **Bug Fixes**: + - Fixed Rift/Vive controller drift when using ZED's tracking instead of the HMD's + - Changed the previously hard-coded layers the ZED plugin used (8-11) to be adjusted in the Inspector, and set them to 28-31 by default + - Changed greenscreen config file loading so that it will work in a build when placed in a Resources folder, and changed default save path accordingly + - Clarified error messages from playing SVOs in loop mode with tracking enabled + + + * **Compatibility**: + - Compatible with ZED SDK 2.7, CUDA 9.0 or 10.0. + + +###2.7.1 + + * **Features/Improvements**: + - Added option to enable/disable the skybox at start in ZEDManager -> Advanced Settings. Prior, it was always disabled. + - ZEDManager now automatically names the layers it uses (27-30 by default) so long as they don't already have names. This makes them visible in layer drop-downs, + making it much clearer how the plugin uses these layers. Big thanks to Andrea Brunori for suggesting the method used to achieve this. + - ZEDManager's default layers changed from 28-31 to 27-30 to avoid conflicting with Unity rendering in the Inspector. Another thanks to Andrea + for pointing out this conflict. + - Global lighting settings in all demo scenes are now similar to avoid confusion. + - Removed outdated controller scripts ZEDOculusControllerManager and ZEDSteamVRControllerManager. These have been deprecated for several versions. + Use ZEDControllerTracker instead. + + * **Bug Fixes**: + - Fixed the visibility and physics of planes detected by ZEDPlaneDetectionManager not being updated if the global visibility/physics values + were updated by a script when the Inspector wasn't visible. See planesHavePhysics, planesVisibleInScene and planesVisibleInGame within ZEDPlaneDetectionManager. + - Fixed Oculus Integration and SteamVR Plugin packages not being detected if their folders were renamed, or placed anywhere but the root /Assets/ folder. + - Fixed ZEDControllerTracker causing ZED rig to float away when ZED rig is a child of it (due to drift correction) + - Fixed hidden AR rig not appearing in the Hierarchy if Show AR Rig in ZEDManager's Advanced Settings was set to true on start. + +### 2.7.0 + + * **Features/Bug Fixes**: + - Fixed Rift/Vive controller drift when using ZED's tracking instead of the HMD's. + - Changed the previously hard-coded layers the ZED plugin used (8-11) to be adjusted in the Inspector, and set them to 28-31 by default. + - Added toggle box to reveal a camera rig used for final HMD output, normally hidden, for advanced users. + - Added toggle boxes for the fade-in effect when the ZED initializes, and setting the ZED rig Gameobject to DontDestroyOnLoad on start. + - Changed greenscreen config file loading so that it will work in a build when placed in a Resources folder, and changed default save path accordingly. + - Clarified error messages from playing SVOs in loop mode with tracking enabled. + + + +### 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.6, CUDA 9.0 or 9.2. + + +### 2.5.0 + * **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. + + + * **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**: + - Compatible with ZED SDK 2.5, CUDA 9.0 or 9.2. + + +### 2.4.1 + - **Features**: + - Add Full IMUData access to get angular velocity and linear acceleration through ZEDCamera.GetInternalIMUData() function. + + - **Examples**: + - Modified Dark room sample into a AR "night club" light show to show how to use ZED Manager's camera brightness settings and ZEDLight script. + - Update Object Placement sample and doc. + + - **Bug Fixes**: + - Fix ZEDManager's camera brightness settings through scripting. + - Fix Normal and Center on plane's detection. Refactor ZEDPlaneGameObject as MonoBehavior. + - Fix ZED Rig Mono image when game is built due to rendering path. + - Fix crash when moving SVO playback playhead. + - Fix Camera settings spamming errors due to pluginIsReady value not set. + - Fix loading screen blank on left eye at specific rotations (180deg). + - Fix Depth occlusion setting in Rig mono. + - Fix greenscreen wrong config file that breaks the GreenScreen example if not found. + - Remove "Restart Camera" when changing Depth occlusions as it was not needed. + + - **Compatibility**: + - Add Vive Pro support as VR headset (not with the Vive's cameras). + + +### 2.4.0 + - **Features**: + - Added plane detection : + - ZEDPlaneDetectionManager.cs interfaces with the SDK. Click on the screen to add planes when detected, or specify a screen-space location with DetectPlaneAtHit(). A specific function for floor detection DetectFloorPlane() is provided (as well as a GUI button access). ZEDPlaneDetectionManager inherits from MonoBehavior and must be used to have access to plane detection in Unity Scene. + - ZEDPlaneGameObject.cs represents a plane with info about its position, rotation, boundaries, etc. It also creates a GameObject representation of the plane that supports collisions and rendering. + - ZEDPlaneRenderer.cs (automatically created by ZEDPlaneDetectionManager) displays a scene's planes overlapping other objects so that planes highlight real-world features instead of appearing distinct from them. + - Added HitTest multiple support functions for Real / Virtual world collision when no spatial mapping is used (Beta). + - Added prompt for recommended settings on import, most notably MSAA x4 and Linear color space. + - Added changing resolution, depth mode, and other options in ZEDManager at runtime (requires restarting the camera). + - The ZED can now be reconnected mid-scene after being disconnected. + - Scanned meshes, SVOs, greenscreen configuration files and .area files are now saved in /Assets/ by default rather than the root project folder. This makes them accessible in the Project tab within Unity. + + - **Bug Fixes**: + - Fixed wrong transformation for Normal vector in World reference frame, causing object placement sometimes unstable. + - Fixed incorrect reports of bandwidth issues when set to 1080p resolution. + - Fixed alert about missing IMU before enough time has passed to find it. + - Updated broken prefab references in Spatial Mapping sample and prefabs + - Fixed Depth Occlusion option on ZEDManager only being changable at runtime, and only applying to the left eye in stereo mode. + - Added proper error message when scene is started without the ZED SDK installed + - Removed missing sdk window popup when play/pause is pressed. This window now only shows up when Unity is loaded. + - Fixed broken Pause button on ZEDSVOManager. + - Fixed the ZED stream not properly closing if ZEDManager was disabled or destroyed when the scene ended. This would result in problems connecting to the ZED until the ZED is replugged or the computer is restarted. + - Fixed issue causing the loading screen to be heavily pixelated in stereo mode. + - Fixed flashing errors in loading screen (when an error occurs). + - Specifying an invalid .area file for spatial memory no longer causes tracking to be disabled; the file is now ignored. + - Fixed directionnal light on Object Placement scene. + - Hide Rendering planes of ZED_Rig_Stereo prefab in the scene when game is not started. + + - **Examples**: + - Modified lighting, animations and navigation in ZomBunny prefab for Spatial Mapping and Object Placement samples to make it appear more realistic. + - PlaceOnScreen.cs (Object Placement) now instantiates new objects on click rather than moving around a pre-existing object. + + - **Renaming**: + - Renaming getDepthAtxxx() and getDistanceAtxxx() support functions in getForwardDistanceAtxxx() and getEuclideanDistanceAtxxx() for better understanding. + + - **Compatibility**: + - Updated Oculus Package detection ("OVR" becomes "Oculus") in ZEDOculusControllerManager.cs + + +### 2.3.3 +- **Features**: + - Updated ZEDCamera.cs script to include GetInternalIMUOrientation function to get access to internal imu quaternion of the ZED-M. + - Improved VAR (timewarp) when using HTC Vive in stereo pass-through. + +- **Bug Fixes**: + - Fixed camera FPS stats display when camera is disconnected. It shows now "disconnected" instead of the last camera FPS. + + + +### 2.3.2 +- **Features**: + - Updated ZEDCamera.cs script to include setIMUPrior(sl::Transform) function used for video pass-through. + - Added Camera FPS, Engine FPS, Tracking Status, HMD and Plugin version in ZED Manager panel. These status will help developers see where the application's bottlenecks are. +A Camera FPS below 60FPS indicates a USB bandwidth issue. An Engine FPS below 90FPS indicates that rendering is the limiting factor. Both will induce drop frames. +Note that building and running your application greatly improves performance compared to playing the scene in Unity Editor + - Added automatic detection of OVR package to avoid having to manually define "ZED_OCULUS" in project settings when using ZEDOculusControllerManager. + - Added compression settings (RAW, LOSSLESS, LOSSY) in ZEDSVOManager.cs script. + +- **Bug Fixes**: + - Fixed initial camera position when using ZED Mini and an HMD. This had an impact on virtual objects created with physical gravity up and spatial mapping mesh origin. + - Fixed enable/disable depth occlusions settings in Deferred rendering mode. + - Fixed resize of halo effect in the Planetarium example. + - Fixed garbage matte behavior in GreenScreen example that displayed anchor spheres in the scene after loading a matte + - Fixed ZED Manager instance creation to respect MonoBehavior implementation. Only one ZED manager instance is available at a time for an application. + - Fix Loading message when ZED tries to open. + - Remove BallLauncher message instruction as gameobject, as it was not used. + +### 2.3.1 +- **Minor Bug fixes and Features** : + - Fix GreenScreen broken prefab in Canvas. + - Fix default spatial memory path when enableTracking is true. Could throw an exception when tracking was activated in green screen prefab. + - Fix missing but unused script in Planetarium prefab + - Added Unity Plugin version in ZEDCamera.cs + +### 2.3.0 +- **Features**: + - Added support for ZED mini. + - Added beta stereo passthrough feature with optimized rendering in VR headsets (only with ZED mini) +- **Prefabs**: + - Added ZED_Rig_Stereo prefab, with stereo capture and stereo rendering to VR headsets (beta version) + - Renamed ZED_Rig_Left in ZED_Rig_Mono, for better mono/stereo distinction. +- **Examples**: + - Added Planetarium scene to demonstrate how to re-create the solar system in the real world. This is a simplified version of the ZEDWorld app. + - Added Dark Room scene to demonstrate how to decrease the brightness of the real world using the "Real Light Brightness" setting in ZEDManager.cs. + - Added Object Placement scene to demonstrate how to place an object on a horizontal plane in the real world. +- **Scripts**: + - Added ZEDSupportFunctions.cs to help using depth and normals at a screen or world position. Some of these functions are used in ObjectPlacement scene. + - Added ZEDMixedRealityPlugin.cs to handle stereo passthrough in Oculus Rift or HTC Vive Headset. +- **Renaming**: + - ZEDTextureOverlay.cs has been renamed ZEDRenderingPlane.cs. +- **Compatibility**: + - Supports ZED SDK v2.3.0 + - Supports Unity 2017.x.y (with automatic updates from Unity). +- **Known Issues**: + - On certain configurations, VRCompositor in SteamVR can freeze when using HTC Vive and ZED. Disabling Async Reprojection in SteamVR's settings can fix the issue. + - The stereo passthrough experience is highly sensitive to Capture/Engine FPS. Here are some tips: + * Make sure your PC meets the requirements for stereo pass-through AR (GTx 1070 or better). + * Make sure you don't have other resource-intensive applications running on your PC at the same time as Unity. + * Test your application in Build mode, rather than the Unity editor, to have the best FPS available. + +### 2.2.0/2.1.0/2.0.0 +See ZED SDK release notes. diff --git a/Assets/ZED/Doc/ReleaseNotes.md.meta b/Assets/ZED/Doc/ReleaseNotes.md.meta new file mode 100644 index 0000000..376d6dc --- /dev/null +++ b/Assets/ZED/Doc/ReleaseNotes.md.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ace2a5d4211709245b3c7249eb366966 +timeCreated: 1515608218 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Editor.meta b/Assets/ZED/Editor.meta new file mode 100644 index 0000000..b9b2cd6 --- /dev/null +++ b/Assets/ZED/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 34211591d992f6e4988e8e8f41407dfd +folderAsset: yes +timeCreated: 1488815750 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Editor/Scripts.meta b/Assets/ZED/Editor/Scripts.meta new file mode 100644 index 0000000..d4beacb --- /dev/null +++ b/Assets/ZED/Editor/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c9374f60fa3c3274f91782a8c8cdd600 +folderAsset: yes +timeCreated: 1543443411 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Editor/Scripts/BuildScript.cs b/Assets/ZED/Editor/Scripts/BuildScript.cs new file mode 100644 index 0000000..d5dbb2f --- /dev/null +++ b/Assets/ZED/Editor/Scripts/BuildScript.cs @@ -0,0 +1,8 @@ +using UnityEditor; +class BuildScript +{ + static void CreateCSProj() + { + EditorApplication.ExecuteMenuItem("Assets/Open C# Project"); + } +} \ No newline at end of file diff --git a/Assets/ZED/Editor/Scripts/BuildScript.cs.meta b/Assets/ZED/Editor/Scripts/BuildScript.cs.meta new file mode 100644 index 0000000..9632861 --- /dev/null +++ b/Assets/ZED/Editor/Scripts/BuildScript.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c0781a646f0b3784b836b88a69064947 +timeCreated: 1543443417 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs b/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs new file mode 100644 index 0000000..3cfb462 --- /dev/null +++ b/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs @@ -0,0 +1,1063 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +using UnityEngine; +using UnityEditor; + +/// +/// 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 later with CheckChange(). + //These do not need to be SerializedProperties because they're only used for checking recent changes. + sl.RESOLUTION resolution; + sl.DEPTH_MODE depthmode; + bool usespatialmemory; + + + //Input Prop + private SerializedProperty cameraIDProperty; + private SerializedProperty inputTypeProperty; + private SerializedProperty depthModeProperty; + private SerializedProperty usbResolutionProperty; + private SerializedProperty usbFPSProperty; + private SerializedProperty svoFileNameProperty; + private SerializedProperty svoLoopProperty; + private SerializedProperty svoRealTimeModeProperty; + private SerializedProperty pauseSVOProperty; + private SerializedProperty currentFrameSVOProperty; + private SerializedProperty maxFrameSVOProperty; + + private SerializedProperty streamIPProperty; + private SerializedProperty streamPortProperty; + //Tracking Prop + private SerializedProperty enableTrackingProperty; + private SerializedProperty enableSMProperty; + private SerializedProperty pathSMProperty; + private SerializedProperty estimateIPProperty; + + //Rendering Prop + private SerializedProperty depthOcclusionProperty; + private SerializedProperty arpostProcessingPropery; + private SerializedProperty camBrightnessProperty; + + + //Recording Prop + private SerializedProperty svoOutputFileNameProperty; + private SerializedProperty svoOutputCompressionModeProperty; + + //Streaming Prop + private SerializedProperty streamingOutProperty; + private SerializedProperty streamingOutCodecProperty; + private SerializedProperty streamingOutPortProperty; + private SerializedProperty streamingOutBitrateProperty; + private SerializedProperty streamingOutGopSizeProperty; + private SerializedProperty streamingOutAdaptBitrateProperty; + + + /// + /// Layout option used to draw the '...' button for opening a File Explorer window to find a mesh file. + /// + private GUILayoutOption[] optionsButtonBrowse = { GUILayout.MaxWidth(30) }; + private GUILayoutOption[] optionsButtonStandard = { /*GUILayout.(EditorGUIUtility.labelWidth)*/}; + + + /// + /// Text on the mesh visibility button. Switches between 'Hide Mesh' and 'Display Mesh'. + /// + private string displayText = "Hide Mesh"; + /// + /// Serialized version of ZEDSpatialMappingManager's range_preset property. + /// + private SerializedProperty range; + /// + /// Serialized version of ZEDSpatialMappingManager's resolution_preset property. + /// + private SerializedProperty mappingResolution; + /// + /// 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; + + SerializedProperty sensingModeProperty; + SerializedProperty maxDepthProperty; + SerializedProperty confidenceThresholdProperty; + SerializedProperty showarrig; + SerializedProperty greyskybox; + SerializedProperty fadeinonstart; + SerializedProperty dontdestroyonload; + SerializedProperty arlayer; + SerializedProperty setIMUPrior; + + SerializedProperty showadvanced; //Show advanced settings or not. + SerializedProperty showSpatialMapping; //Show spatial mapping or not. + SerializedProperty showRecording; //Show recording or not. + SerializedProperty showStreamingOut; //Show streaming out or not + SerializedProperty showcamcontrol; //Show cam control settings or not. + + + /// + /// Default value for camera controls + /// + private const int cbrightness = 4; + private const int ccontrast = 4; + private const int chue = 0; + private const int csaturation = 4; + private const int cwhiteBalance = 2600; + + /// + /// Current value for camera controls + /// + private int brightness = 4; + private int contrast = 4; + private int hue = 0; + private int saturation = 4; + + private bool aex_agc_control = true; + private int exposure; + private int gain; + + private bool awb_control = true; + private int whitebalance; + private bool ledStatus = true; + + /// + /// Whether we've set a manual value to gain and exposure or if they're in auto mode. + /// + private bool setManualValue = true; + /// + /// Whether we've set a manual value to white balance or if it's in auto mode. + /// + private bool setManualWhiteBalance = true; + + private string[] toolbarStrings = new string[] { "USB", "SVO", "Stream" }; + private string pauseText = "Pause"; + private string pauseTooltip = " SVO playback or recording."; //Appended to the pause Text to make tooltip text. + private string[] filters = { "Svo files", "svo" }; //Filters used for browsing for an SVO. + + private void OnEnable() + { + manager = (ZEDManager)target; + + + resolution = manager.resolution; + depthmode = manager.depthMode; + usespatialmemory = manager.enableSpatialMemory; + + //Input Serialized Property + cameraIDProperty = serializedObject.FindProperty("cameraID"); + depthModeProperty = serializedObject.FindProperty("depthMode"); + inputTypeProperty = serializedObject.FindProperty("inputType"); + usbResolutionProperty = serializedObject.FindProperty("resolution"); + usbFPSProperty = serializedObject.FindProperty("FPS"); + svoFileNameProperty = serializedObject.FindProperty("svoInputFileName"); + svoLoopProperty = serializedObject.FindProperty("svoLoopBack"); + svoRealTimeModeProperty = serializedObject.FindProperty("svoRealTimeMode"); + streamIPProperty = serializedObject.FindProperty("streamInputIP"); + streamPortProperty = serializedObject.FindProperty("streamInputPort"); + pauseSVOProperty = serializedObject.FindProperty("pauseSVOReading"); + currentFrameSVOProperty = serializedObject.FindProperty("currentFrame"); + maxFrameSVOProperty = serializedObject.FindProperty("numberFrameMax"); + + //Tracking Serialized Property + enableTrackingProperty = serializedObject.FindProperty("enableTracking"); + enableSMProperty = serializedObject.FindProperty("enableSpatialMemory"); + pathSMProperty = serializedObject.FindProperty("pathSpatialMemory"); + estimateIPProperty = serializedObject.FindProperty("estimateInitialPosition"); + + + ///Rendering Serialized Property + depthOcclusionProperty = serializedObject.FindProperty("depthOcclusion"); + arpostProcessingPropery = serializedObject.FindProperty("postProcessing"); + camBrightnessProperty = serializedObject.FindProperty("m_cameraBrightness"); + + ////////////////////////////////////////////////// FoldOut + showadvanced = serializedObject.FindProperty("advancedPanelOpen"); + showSpatialMapping = serializedObject.FindProperty("spatialMappingFoldoutOpen"); + showcamcontrol = serializedObject.FindProperty("camControlFoldoutOpen"); + showRecording = serializedObject.FindProperty("recordingFoldoutOpen"); + showStreamingOut = serializedObject.FindProperty("streamingOutFoldoutOpen"); + + + ///Spatial Mapping Serialized Property + range = serializedObject.FindProperty("mappingRangePreset"); + mappingResolution = serializedObject.FindProperty("mappingResolutionPreset"); + isFilteringEnable = serializedObject.FindProperty("isMappingFilteringEnable"); + filterParameters = serializedObject.FindProperty("meshFilterParameters"); + isTextured = serializedObject.FindProperty("isMappingTextured"); + saveWhenOver = serializedObject.FindProperty("saveMeshWhenOver"); + meshPath = serializedObject.FindProperty("meshPath"); + + ///Recording Serialized Property + svoOutputFileNameProperty = serializedObject.FindProperty("svoOutputFileName"); + svoOutputCompressionModeProperty = serializedObject.FindProperty("svoOutputCompressionMode"); + + streamingOutProperty = serializedObject.FindProperty("enableStreaming"); + streamingOutCodecProperty = serializedObject.FindProperty("streamingCodec"); + streamingOutPortProperty = serializedObject.FindProperty("streamingPort"); + streamingOutBitrateProperty = serializedObject.FindProperty("bitrate"); + streamingOutGopSizeProperty = serializedObject.FindProperty("gopSize"); + streamingOutAdaptBitrateProperty = serializedObject.FindProperty("adaptativeBitrate"); + + + ///Advanced Settings Serialized Property + arlayer = serializedObject.FindProperty("arlayer"); + showarrig = serializedObject.FindProperty("showarrig"); + fadeinonstart = serializedObject.FindProperty("fadeInOnStart"); + greyskybox = serializedObject.FindProperty("greySkybox"); + dontdestroyonload = serializedObject.FindProperty("dontDestroyOnLoad"); + showarrig = serializedObject.FindProperty("showarrig"); + sensingModeProperty = serializedObject.FindProperty("sensingMode"); + maxDepthProperty = serializedObject.FindProperty("m_maxDepthRange"); + confidenceThresholdProperty = serializedObject.FindProperty("m_confidenceThreshold"); + setIMUPrior = serializedObject.FindProperty("setIMUPriorInAR"); + } + + public override void OnInspectorGUI() + { + GUIStyle boldfoldout = new GUIStyle(EditorStyles.foldout); + boldfoldout.fontStyle = FontStyle.Bold; + //DrawDefaultInspector(); //Draws what you'd normally see in the inspector in absence of a custom inspector. + + EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth * 0.4f; + /////////////////////////////////////////////////////////////// + /// Inputlayout ///////////////////////////////// + ///////////////////////////////////////////////////////////// + GUILayout.Space(10); + EditorGUILayout.LabelField("Input", EditorStyles.boldLabel); + GUILayout.Space(5); + EditorGUI.indentLevel++; + GUIContent cameraIDLabel = new GUIContent("Camera ID", "Camera ID in Plugin. Used in Multicam configuration"); + cameraIDProperty.enumValueIndex = (int)(sl.ZED_CAMERA_ID)EditorGUILayout.EnumPopup(cameraIDLabel, (sl.ZED_CAMERA_ID)cameraIDProperty.enumValueIndex); + + GUIContent cameraDepthModeLabel = new GUIContent("Depth Mode", "Camera depth mode"); + depthModeProperty.enumValueIndex = (int)(sl.DEPTH_MODE)EditorGUILayout.EnumPopup(cameraDepthModeLabel, (sl.DEPTH_MODE)depthModeProperty.enumValueIndex); + GUILayout.Space(15); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Input Type", GUILayout.Width(EditorGUIUtility.labelWidth)); + GUI.enabled = !Application.isPlaying; + inputTypeProperty.intValue = GUILayout.Toolbar(inputTypeProperty.intValue, toolbarStrings, GUILayout.ExpandWidth(true)); + GUI.enabled = true; + EditorGUILayout.EndHorizontal(); + GUILayout.Space(5); + switch (inputTypeProperty.intValue) + { + case 0: + GUIContent cameraResolutionLabel = new GUIContent("Resolution", "Camera resolution"); + //GUI.enabled = !Application.isPlaying; + usbResolutionProperty.enumValueIndex = (int)(sl.RESOLUTION)EditorGUILayout.EnumPopup(cameraResolutionLabel, (sl.RESOLUTION)usbResolutionProperty.enumValueIndex); + //GUI.enabled = true; + GUIContent cameraFPSLabel = new GUIContent("FPS", "Camera FPS"); + GUI.enabled = !Application.isPlaying; + usbFPSProperty.intValue = EditorGUILayout.IntField(cameraFPSLabel, usbFPSProperty.intValue); + GUI.enabled = true; + serializedObject.ApplyModifiedProperties(); + + //Check if we need to restart the camera, and create a button for the user to do so. + if (Application.isPlaying && manager.IsZEDReady && CheckChange()) + { + GUILayout.Space(10); + GUIStyle orangetext = new GUIStyle(EditorStyles.label); + orangetext.normal.textColor = Color.red; + orangetext.wordWrap = true; + string labeltext = "Settings have changed that require restarting the camera to apply."; + Rect labelrect = GUILayoutUtility.GetRect(new GUIContent(labeltext, ""), orangetext); + EditorGUI.LabelField(labelrect, labeltext, orangetext); + + if (GUILayout.Button("Restart Camera")) + { + manager.Reset(); //Reset the ZED. + + //Reset the fields now that they're synced. + resolution = manager.resolution; + depthmode = manager.depthMode; + + } + } + + break; + + case 1: + EditorGUILayout.BeginHorizontal(); + GUIContent svoFileNameLabel = new GUIContent("SVO File", "SVO file name"); + GUI.enabled = !Application.isPlaying; + svoFileNameProperty.stringValue = EditorGUILayout.TextField(svoFileNameLabel, svoFileNameProperty.stringValue); + GUIContent loadSVOlabel = new GUIContent("...", "Browse for existing SVO file."); + if (GUILayout.Button(loadSVOlabel, optionsButtonBrowse)) + { + svoFileNameProperty.stringValue = EditorUtility.OpenFilePanelWithFilters("Load SVO", "", filters); + } + GUI.enabled = true; + EditorGUILayout.EndHorizontal(); + GUIContent svoLoopLabel = new GUIContent("Loop SVO", "Loop SVO when it reaches the end"); + svoLoopProperty.boolValue = EditorGUILayout.Toggle(svoLoopLabel, svoLoopProperty.boolValue); + GUIContent svoRealTimeModelabel = new GUIContent("Real-Time mode", "Read SVO in real time mode"); + svoRealTimeModeProperty.boolValue = EditorGUILayout.Toggle(svoRealTimeModelabel, svoRealTimeModeProperty.boolValue); + EditorGUI.BeginChangeCheck(); + + GUI.enabled = (manager.NumberFrameMax > 0); + GUIContent sliderlabel = new GUIContent("Frame ", "SVO playback position"); + currentFrameSVOProperty.intValue = EditorGUILayout.IntSlider(sliderlabel, currentFrameSVOProperty.intValue, 0, maxFrameSVOProperty.intValue); + if (EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera != null) + { + //If the slider of frame from the SVO has moved, manually grab the frame and update the textures. + manager.zedCamera.SetSVOPosition(currentFrameSVOProperty.intValue); + if (pauseSVOProperty.boolValue) + { + manager.NeedNewFrameGrab = true; + } + } + } + GUI.enabled = false; + + if (manager.zedCamera != null) + GUI.enabled = manager.zedCamera.IsCameraReady; + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(EditorGUIUtility.labelWidth); + pauseText = pauseSVOProperty.boolValue ? "Resume" : "Pause"; + GUIContent pauselabel = new GUIContent(pauseText, pauseText + pauseTooltip); + if (GUILayout.Button(pauselabel)) + { + pauseSVOProperty.boolValue = !pauseSVOProperty.boolValue; + } + EditorGUILayout.EndHorizontal(); + GUI.enabled = true; + serializedObject.ApplyModifiedProperties(); + break; + + case 2: + GUIContent streamIPLabel = new GUIContent("IP", "IP of streaming device"); + GUI.enabled = !Application.isPlaying; + streamIPProperty.stringValue = EditorGUILayout.TextField(streamIPLabel, streamIPProperty.stringValue); + GUI.enabled = true; + GUIContent streamPortLabel = new GUIContent("Port", "Port where stream is sent to "); + GUI.enabled = !Application.isPlaying; + streamPortProperty.intValue = EditorGUILayout.IntField(streamPortLabel, streamPortProperty.intValue); + GUI.enabled = true; + serializedObject.ApplyModifiedProperties(); + break; + } + + EditorGUI.indentLevel--; + /////////////////////////////////////////////////////////////// + /// Motion Tracking layout ///////////////////////////////// + ///////////////////////////////////////////////////////////// + GUILayout.Space(10); + EditorGUILayout.LabelField("Motion Tracking", EditorStyles.boldLabel); + GUILayout.Space(5); + EditorGUI.indentLevel++; + GUIContent enableTrackingLabel = new GUIContent("Enable Tracking", "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."); + enableTrackingProperty.boolValue = EditorGUILayout.Toggle(enableTrackingLabel, enableTrackingProperty.boolValue); + + GUIContent enableSMPropertyLabel = new GUIContent("Enable Spatial Memory", "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"); + enableSMProperty.boolValue = EditorGUILayout.Toggle(enableSMPropertyLabel, enableSMProperty.boolValue); + + GUIContent pathSMlabel = new GUIContent("Path Spatial Memory", "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."); + pathSMProperty.stringValue = EditorGUILayout.TextField(pathSMlabel, pathSMProperty.stringValue); + + GUIContent estimateIPPropertyLabel = new GUIContent("Estimate Initial Position", "Estimate initial position by detecting the floor. Leave it false if using VR Headset"); + estimateIPProperty.boolValue = EditorGUILayout.Toggle(estimateIPPropertyLabel, estimateIPProperty.boolValue); + EditorGUI.indentLevel--; + + /////////////////////////////////////////////////////////////// + /// Rendering layout ///////////////////////////////// + ///////////////////////////////////////////////////////////// + GUILayout.Space(10); + EditorGUILayout.LabelField("Rendering", EditorStyles.boldLabel); + GUILayout.Space(5); + EditorGUI.indentLevel++; + GUIContent depthOcclusionPropertyLabel = new GUIContent("Depth Occlusion", "When enabled, the real world can occlude (cover up) virtual objects that are behind it. " + + "Otherwise, virtual objects will appear in front."); + depthOcclusionProperty.boolValue = EditorGUILayout.Toggle(depthOcclusionPropertyLabel, depthOcclusionProperty.boolValue); + + GUIContent arpostProcessingProperyLabel = new GUIContent("AR Post-Processing", "Enables post-processing effects on virtual objects that blends them in with the real world."); + arpostProcessingPropery.boolValue = EditorGUILayout.Toggle(arpostProcessingProperyLabel, arpostProcessingPropery.boolValue); + + GUIContent camBrightnessPropertyLabel = new GUIContent("Camera Brightness", "Brightness of the final real-world image. Default is 100. 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."); + camBrightnessProperty.intValue = EditorGUILayout.IntSlider(camBrightnessPropertyLabel, camBrightnessProperty.intValue, 0, 100); + EditorGUI.indentLevel--; + + /////////////////////////////////////////////////////////////// + /// Spatial Mapping layout ///////////////////////////////// + ///////////////////////////////////////////////////////////// + GUILayout.Space(10); + showSpatialMapping.boolValue = EditorGUILayout.Foldout(showSpatialMapping.boolValue, "Spatial Mapping", boldfoldout); + if (showSpatialMapping.boolValue) + { + EditorGUI.indentLevel++; + bool cameraIsReady = false; + + if (manager) + cameraIsReady = manager.zedCamera != null ? manager.zedCamera.IsCameraReady : false; + + displayText = manager.IsSpatialMappingDisplay ? "Hide Mesh" : "Display Mesh"; + + EditorGUILayout.BeginHorizontal(); + + GUILayout.Space(5); + + EditorGUILayout.EndHorizontal(); + + 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, manager.mappingResolutionPreset); + if (newResolution != manager.mappingResolutionPreset) + { + mappingResolution.enumValueIndex = (int)newResolution; + serializedObject.ApplyModifiedProperties(); + } + + 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, manager.mappingRangePreset); + if (newRange != manager.mappingRangePreset) + { + range.enumValueIndex = (int)newRange; + serializedObject.ApplyModifiedProperties(); + } + + EditorGUILayout.BeginHorizontal(); + 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 = !manager.IsMappingRunning; //Don't allow changing the texturing setting while the scan is running. + + 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; //Gray out below elements if the ZED hasn't been initialized as you can't yet start a scan. + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(EditorGUIUtility.labelWidth); + if (!manager.IsMappingRunning) + { + GUIContent startmappinglabel = new GUIContent("Start Spatial Mapping", "Begin the spatial mapping process."); + if (GUILayout.Button(startmappinglabel)) + { + if (!manager.IsSpatialMappingDisplay) + { + manager.SwitchDisplayMeshState(true); + } + manager.StartSpatialMapping(); + } + } + else + { + if (manager.IsMappingRunning && !manager.IsMappingUpdateThreadRunning || manager.IsMappingRunning && manager.IsMappingTexturingRunning) + { + GUILayout.FlexibleSpace(); + GUIContent finishinglabel = new GUIContent("Spatial mapping is finishing", "Please wait - the mesh is being processed."); + GUILayout.Label(finishinglabel); + Repaint(); + GUILayout.FlexibleSpace(); + } + else + { + GUIContent stopmappinglabel = new GUIContent("Stop Spatial Mapping", "Ends spatial mapping and begins processing the final mesh."); + if (GUILayout.Button(stopmappinglabel)) + { + manager.StopSpatialMapping(); + } + } + } + + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUI.enabled = cameraIsReady; + string displaytooltip = manager.IsSpatialMappingDisplay ? "Hide the mesh from view." : "Display the hidden mesh."; + GUILayout.Space(EditorGUIUtility.labelWidth); + GUIContent displaylabel = new GUIContent(displayText, displaytooltip); + if (GUILayout.Button(displayText)) + { + manager.SwitchDisplayMeshState(!manager.IsSpatialMappingDisplay); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + GUIContent clearMesheslabel = new GUIContent("Clear All Meshes", "Clear all meshes created with the ZED"); + GUILayout.Space(EditorGUIUtility.labelWidth); + if (GUILayout.Button(clearMesheslabel)) + { + manager.ClearAllMeshes(); + } + EditorGUILayout.EndHorizontal(); + GUI.enabled = true; + + GUILayout.Space(5); + EditorGUILayout.LabelField("Storage", EditorStyles.boldLabel); + + 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(); + + 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); + + 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(); + } + + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + + GUILayout.FlexibleSpace(); + + GUI.enabled = System.IO.File.Exists(meshPath.stringValue) && cameraIsReady; + GUIContent loadlabel = new GUIContent("Load", "Load an existing mesh and .area file into the scene."); + if (GUILayout.Button(loadlabel)) + { + manager.LoadMesh(meshPath.stringValue); + } + + EditorGUILayout.EndHorizontal(); + GUI.enabled = true; + EditorGUI.indentLevel--; + + } + serializedObject.ApplyModifiedProperties(); + + /////////////////////////////////////////////////////////////// + /// Recording layout ///////////////////////////////// + ///////////////////////////////////////////////////////////// + GUILayout.Space(10); + showRecording.boolValue = EditorGUILayout.Foldout(showRecording.boolValue, "Recording", boldfoldout); + if (showRecording.boolValue) + { + + EditorGUI.indentLevel++; + GUILayout.Space(5); + bool cameraIsReady = false; + if (manager) + cameraIsReady = manager.zedCamera != null ? manager.zedCamera.IsCameraReady : false; + + GUIContent svoOutFileNameLabel = new GUIContent("SVO File", "SVO file name"); + svoOutputFileNameProperty.stringValue = EditorGUILayout.TextField(svoOutFileNameLabel, svoOutputFileNameProperty.stringValue, GUILayout.ExpandWidth(true)); + + GUIContent svoCompressionModeLabel = new GUIContent("SVO Compression", "SVO Compression mode for the recorded SVO file"); + svoOutputCompressionModeProperty.enumValueIndex = (int)(sl.SVO_COMPRESSION_MODE)EditorGUILayout.EnumPopup(svoCompressionModeLabel, (sl.SVO_COMPRESSION_MODE)svoOutputCompressionModeProperty.enumValueIndex, GUILayout.ExpandWidth(true)); + + EditorGUILayout.BeginHorizontal(); + GUI.enabled = cameraIsReady; + string recordLabel = manager.needRecordFrame ? "Stop Recording" : "Start Recording"; + string recordtooltip = manager.needRecordFrame ? "Stop Recording" : "Start Recording"; + GUIContent displaylabel = new GUIContent(recordLabel, recordtooltip); + GUILayout.Space(EditorGUIUtility.labelWidth); + if (GUILayout.Button(recordLabel)) + { + if (manager.needRecordFrame) + { + manager.zedCamera.DisableRecording(); + manager.needRecordFrame = false; + } + else + { + + if (manager.zedCamera.EnableRecording(svoOutputFileNameProperty.stringValue, (sl.SVO_COMPRESSION_MODE)svoOutputCompressionModeProperty.enumValueIndex) == sl.ERROR_CODE.SUCCESS) + manager.needRecordFrame = true; + else + { + Debug.LogError("Failed to start SVO Recording"); + manager.needRecordFrame = false; + } + } + } + EditorGUI.indentLevel--; + GUI.enabled = true; + EditorGUILayout.EndHorizontal(); + } + + + /////////////////////////////////////////////////////////////// + /// Streaming Out layout ///////////////////////////////// + ///////////////////////////////////////////////////////////// + GUILayout.Space(10); + showStreamingOut.boolValue = EditorGUILayout.Foldout(showStreamingOut.boolValue, "Streaming", boldfoldout); + if (showStreamingOut.boolValue) + { + EditorGUI.indentLevel++; + GUILayout.Space(5); + GUIContent streamingOutPropertyLabel = new GUIContent("Enable Streaming Output", "Enable Streaming Output with below settings"); + streamingOutProperty.boolValue = EditorGUILayout.Toggle(streamingOutPropertyLabel, streamingOutProperty.boolValue); + + GUIContent streamingOutCodecPropertyLabel = new GUIContent("Codec", "Codec used for images compression"); + streamingOutCodecProperty.enumValueIndex = (int)(sl.STREAMING_CODEC)EditorGUILayout.EnumPopup(streamingOutCodecPropertyLabel, (sl.STREAMING_CODEC)streamingOutCodecProperty.enumValueIndex); + + GUIContent streamingOutPortPropertyLabel = new GUIContent("Port", "Port where stream is sent to "); + streamingOutPortProperty.intValue = EditorGUILayout.IntField(streamingOutPortPropertyLabel, streamingOutPortProperty.intValue); + + GUIContent streamingOutBitratePropertyLabel = new GUIContent("Bitrate", "Target Bitrate for the codec"); + streamingOutBitrateProperty.intValue = EditorGUILayout.IntField(streamingOutBitratePropertyLabel, streamingOutBitrateProperty.intValue); + + GUIContent streamingOutGopSizePropertyLabel = new GUIContent("Gop", "Maximum Gop size for the codec"); + streamingOutGopSizeProperty.intValue = EditorGUILayout.IntField(streamingOutGopSizePropertyLabel, streamingOutGopSizeProperty.intValue); + + GUIContent streamingOutAdaptBitratePropertyLabel = new GUIContent("Adaptative Bitrate", "Adaptative bitrate for the codec"); + streamingOutAdaptBitrateProperty.boolValue = EditorGUILayout.Toggle(streamingOutAdaptBitratePropertyLabel, streamingOutAdaptBitrateProperty.boolValue); + EditorGUI.indentLevel--; + } + + + /////////////////////////////////////////////////////////////// + /// Advanced Settings layout /////////////////////////////// + ///////////////////////////////////////////////////////////// + GUILayout.Space(10); + showadvanced.boolValue = EditorGUILayout.Foldout(showadvanced.boolValue, "Advanced Settings", boldfoldout); + if (showadvanced.boolValue) + { + EditorGUI.indentLevel++; + + GUILayout.Space(5); + + GUIContent sensingModeLabel = new GUIContent("Sensing Mode", "FILL approximates depth in areas where depth can't be measured. " + + "FILL is almost always better for augmented/mixed reality applications."); + sensingModeProperty.enumValueIndex = (int)(sl.SENSING_MODE)EditorGUILayout.EnumPopup(sensingModeLabel, (sl.SENSING_MODE)sensingModeProperty.enumValueIndex); + + GUIContent maxDepthPropertyLabel = new GUIContent("Max Depth Range", "Maximum depth at which the camera will display the real world, in meters. " + + "Pixels further than this value will be invisible."); + maxDepthProperty.floatValue = EditorGUILayout.Slider(maxDepthPropertyLabel, maxDepthProperty.floatValue, 0f, 20f); + + GUIContent confidenceThresholdPropertyLabel = new GUIContent("Confidence Threshold", "How tolerant the ZED SDK is to low confidence values. Lower values filter more pixels."); + if (Application.isPlaying) + { + manager.confidenceThreshold = EditorGUILayout.IntSlider(confidenceThresholdPropertyLabel, manager.confidenceThreshold, 0, 100); + } + else + { + confidenceThresholdProperty.intValue = EditorGUILayout.IntSlider(confidenceThresholdPropertyLabel, confidenceThresholdProperty.intValue, 0, 100); + } + + GUILayout.Space(12); + + //Fade In At Start toggle. + GUIContent fadeinlabel = new GUIContent("Fade In at Start", "When enabled, makes the ZED image fade in from black when the application starts."); + fadeinonstart.boolValue = EditorGUILayout.Toggle(fadeinlabel, manager.fadeInOnStart); + + //Grey Skybox toggle. + GUIContent greyskyboxlabel = new GUIContent("Grey Out Skybox on Start", "True to set the background to a neutral gray when the scene starts.\n\r" + + "Recommended for AR so that lighting on virtual objects better matches the real world."); + greyskybox.boolValue = EditorGUILayout.Toggle(greyskyboxlabel, manager.greySkybox); + + //Don't Destroy On Load toggle. + GUIContent dontdestroylabel = new GUIContent("Don't Destroy on Load", "When enabled, applies DontDestroyOnLoad() on the ZED rig in Awake(), " + + "preserving it between scene transitions."); + dontdestroyonload.boolValue = EditorGUILayout.Toggle(dontdestroylabel, manager.dontDestroyOnLoad); + + GUILayout.Space(12); + + //Style for the AR layer box. + GUIStyle layerboxstyle = new GUIStyle(EditorStyles.numberField); + layerboxstyle.fixedWidth = 0; + layerboxstyle.stretchWidth = false; + layerboxstyle.alignment = TextAnchor.MiddleCenter; + + GUIStyle layerboxstylewarning = new GUIStyle(layerboxstyle); + layerboxstylewarning.normal.textColor = new Color(.9f, .9f, 0); //Red color if layer number is invalid. + + GUIStyle layerboxstyleerror = new GUIStyle(layerboxstyle); + layerboxstyleerror.normal.textColor = new Color(.8f, 0, 0); //Red color if layer number is invalid. + + GUIContent arlayerlabel = new GUIContent("AR Layer", "Layer that a final, normally-hidden AR rig sees. Used to confine it from the rest of the scene.\r\n " + + "You can assign this to any empty layer, and multiple ZEDs can share the same layer."); + arlayer.intValue = EditorGUILayout.IntField(arlayerlabel, manager.arLayer, arlayer.intValue < 32 ? layerboxstyle : layerboxstyleerror); + + //Show an error message if the set layer is invalid. + GUIStyle errormessagestyle = new GUIStyle(EditorStyles.label); + errormessagestyle.normal.textColor = layerboxstyleerror.normal.textColor; + errormessagestyle.wordWrap = true; + errormessagestyle.fontSize = 10; + + //Show small error message if user set layer to below zero. + if (arlayer.intValue < 0) + { + string errortext = "Unity layers must be above zero to be visible."; + Rect labelrect = GUILayoutUtility.GetRect(new GUIContent(errortext, ""), errormessagestyle); + EditorGUI.LabelField(labelrect, errortext, errormessagestyle); + } + + //Show small error message if user set layer higher than 31, which is invalid because Unity layers only go up to 31. + if (arlayer.intValue > 31) + { + string errortext = "Unity doesn't support layers above 31."; + Rect labelrect = GUILayoutUtility.GetRect(new GUIContent(errortext, ""), errormessagestyle); + EditorGUI.LabelField(labelrect, errortext, errormessagestyle); + } + + //Show warnings if the layer is valid but not recommended. + GUIStyle warningmessagestyle = new GUIStyle(EditorStyles.label); + warningmessagestyle.normal.textColor = layerboxstylewarning.normal.textColor; + warningmessagestyle.wordWrap = true; + warningmessagestyle.fontSize = 10; + + //Show small warning message if user set layer to 31, which is technically valid but Unity reserves it for other uses. + if (arlayer.intValue == 31) + { + string warningext = "Warning: Unity reserves layer 31 for previews in the editor. Assigning to layer 31 can cause conflicts."; + Rect labelrect = GUILayoutUtility.GetRect(new GUIContent(warningext, ""), warningmessagestyle); + EditorGUI.LabelField(labelrect, warningext, warningmessagestyle); + } + + //Show small warning message if user set layer to 0 + if (arlayer.intValue == 0) + { + string warningext = "Warning: Setting the AR rig to see the Default layer means other objects will be drawn in the background, " + + "and in unexpected positions as the AR rig position is not synced with the ZED_Rig_Stereo object."; + Rect labelrect = GUILayoutUtility.GetRect(new GUIContent(warningext, ""), warningmessagestyle); + EditorGUI.LabelField(labelrect, warningext, warningmessagestyle); + } + + //Show AR Rig toggle. + GUIContent showarlabel = new GUIContent("Show Final AR Rig", "Whether to show the hidden camera rig used in stereo AR mode to " + + "prepare images for HMD output. You normally shouldn't tamper with this rig, but seeing it can be useful for " + + "understanding how the ZED output works."); + bool lastshowar = manager.showARRig; + showarrig.boolValue = EditorGUILayout.Toggle(showarlabel, manager.showARRig); + + if (showarrig.boolValue != lastshowar) + { + LayerMask arlayers = (1 << manager.arLayer); + + if (showarrig.boolValue == true) + { + Tools.visibleLayers |= arlayers; + } + else + { + Tools.visibleLayers &= ~(arlayers); + } + + if (manager.zedRigDisplayer != null && Application.isPlaying) + { + manager.zedRigDisplayer.hideFlags = showarrig.boolValue ? HideFlags.None : HideFlags.HideInHierarchy; + } + } + + GUILayout.Space(12); + + //Whether to set the IMU prior in AR passthrough mode. + GUIContent setimupriorlabel = new GUIContent("Set IMU Prior in AR", "In AR pass-through mode, whether to compare the " + + "ZED's IMU data against the reported position of the VR headset. This helps compensate for drift and should " + + "usually be left on. However, in some setups, like when using a custom mount, this can cause tracking errors."); + setIMUPrior.boolValue = EditorGUILayout.Toggle(setimupriorlabel, manager.setIMUPriorInAR); + + EditorGUI.indentLevel--; + } + + serializedObject.ApplyModifiedProperties(); + + + + /////////////////////////////////////////////////////////////// + /// Camera control layout /////////////////////////////////// + ///////////////////////////////////////////////////////////// + GUILayout.Space(10); + showcamcontrol.boolValue = EditorGUILayout.Foldout(showcamcontrol.boolValue, "Camera Controls", boldfoldout); + if (showcamcontrol.boolValue) + { + GUILayout.Space(5); + EditorGUI.indentLevel++; + if (manager.zedCamera == null) + GUI.enabled = false; + else + GUI.enabled = true; + + + EditorGUI.BeginChangeCheck(); + brightness = EditorGUILayout.IntSlider("Brightness", brightness, 0, 8); + if (EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.BRIGHTNESS, brightness, false); + } + + EditorGUI.BeginChangeCheck(); + contrast = EditorGUILayout.IntSlider("Contrast", contrast, 0, 8); + if (EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.CONTRAST, contrast, false); + } + + EditorGUI.BeginChangeCheck(); + hue = EditorGUILayout.IntSlider("Hue", hue, 0, 11); + if (EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.HUE, hue, false); + } + + EditorGUI.BeginChangeCheck(); + saturation = EditorGUILayout.IntSlider("Saturation", saturation, 0, 8); + if (EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.SATURATION, saturation, false); + } + + EditorGUI.BeginChangeCheck(); + ledStatus = EditorGUILayout.Toggle("LED Status", ledStatus, EditorStyles.toggle); + if (EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + { + int lst = ledStatus ? 1 : 0; + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.LED_STATUS, lst, false); + } + } + + EditorGUI.BeginChangeCheck(); + aex_agc_control = EditorGUILayout.Toggle("AEC / AGC ", aex_agc_control, EditorStyles.toggle); + if (!aex_agc_control && setManualValue && EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + { + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.GAIN, gain, false); + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.EXPOSURE, exposure, false); + setManualValue = false; + } + } + + if (aex_agc_control && EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + { + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.GAIN, gain, true); + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.EXPOSURE, exposure, true); + setManualValue = true; + } + } + + GUI.enabled = !aex_agc_control; + EditorGUI.BeginChangeCheck(); + EditorGUI.indentLevel++; + gain = EditorGUILayout.IntSlider("Gain", gain, 0, 100); + + if (EditorGUI.EndChangeCheck()) + { + if (!aex_agc_control) + { + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.GAIN, gain, false); + } + } + EditorGUI.BeginChangeCheck(); + exposure = EditorGUILayout.IntSlider("Exposure", exposure, 0, 100); + if (EditorGUI.EndChangeCheck()) + { + if (!aex_agc_control) + { + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.EXPOSURE, exposure, false); + } + + } + if (manager.zedCamera == null) + GUI.enabled = false; + else + GUI.enabled = true; + + EditorGUI.indentLevel--; + + EditorGUI.BeginChangeCheck(); + awb_control = EditorGUILayout.Toggle(" AWB ", awb_control, EditorStyles.toggle); + if (!awb_control && setManualWhiteBalance && EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.WHITEBALANCE, whitebalance / 100, false); + setManualWhiteBalance = false; + } + + if (awb_control && EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.WHITEBALANCE, whitebalance / 100, true); + setManualWhiteBalance = true; + } + + EditorGUI.indentLevel++; + EditorGUI.BeginChangeCheck(); + GUI.enabled = !awb_control; + whitebalance = 100 * EditorGUILayout.IntSlider("White balance", whitebalance / 100, 26, 65); + if (!awb_control && EditorGUI.EndChangeCheck()) + { + if (manager.zedCamera.IsCameraReady) + manager.zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.WHITEBALANCE, whitebalance, false); + } + + + + EditorGUI.indentLevel--; + EditorGUI.indentLevel--; + + + GUILayout.Space(7); + if (manager.zedCamera == null) + GUI.enabled = false; + else + GUI.enabled = true; + + EditorGUILayout.BeginHorizontal(); + GUILayout.Space(EditorGUIUtility.labelWidth); + GUIContent camcontrolbuttonreset = new GUIContent("Reset", "Reset camera controls to default"); + if (GUILayout.Button(camcontrolbuttonreset)) + { + manager.zedCamera.ResetCameraSettings(); + manager.zedCamera.RetrieveCameraSettings(); + + brightness = manager.zedCamera.GetCameraSettings().Brightness; + contrast = manager.zedCamera.GetCameraSettings().Contrast; + hue = manager.zedCamera.GetCameraSettings().Hue; + saturation = manager.zedCamera.GetCameraSettings().Saturation; + + awb_control = true; + aex_agc_control = true; + } + + EditorGUILayout.EndHorizontal(); + GUI.enabled = true; + } + serializedObject.ApplyModifiedProperties(); + + + + /////////////////////////////////////////////////////////////// + /// Status layout ////////////////////////////////////////// + ///////////////////////////////////////////////////////////// + + serializedObject.ApplyModifiedProperties(); + + GUIStyle standardStyle = new GUIStyle(EditorStyles.textField); + GUIStyle errorStyle = new GUIStyle(EditorStyles.textField); + errorStyle.normal.textColor = Color.red; + + + GUILayout.Space(10); + EditorGUILayout.LabelField("Status", EditorStyles.boldLabel); + EditorGUI.BeginDisabledGroup(true); + EditorGUI.indentLevel++; + GUILayout.Space(5); + GUIContent cameraModellabel = new GUIContent("Camera Model:", "Model of the targeted camera."); + EditorGUILayout.TextField(cameraModellabel, manager.cameraModel); + + GUIContent cameraSerialNumberlabel = new GUIContent("Camera S/N:", "Serial number of the targeted camera."); + EditorGUILayout.TextField(cameraSerialNumberlabel, manager.cameraSerialNumber); + + GUIContent cameraFWlabel = new GUIContent("Camera Firmware:", "Firmware of the targeted camera."); + EditorGUILayout.TextField(cameraFWlabel, manager.cameraFirmware); + + 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(trackingstatelabel, manager.trackingState, errorStyle); + + GUIContent hmdlabel = new GUIContent("HMD Device:", "The connected VR headset, if any."); + if (Application.isPlaying) + EditorGUILayout.TextField(hmdlabel, manager.HMDDevice); + else + { + //Detect devices through USB. + if (sl.ZEDCamera.CheckUSBDeviceConnected(sl.USB_DEVICE.USB_DEVICE_OCULUS)) + 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(hmdlabel, "-"); + } + EditorGUI.indentLevel--; + EditorGUI.EndDisabledGroup(); + + //TO REMOVE + /*GUILayout.Space(20); + 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. + /// 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) + { + return true; + } + else return false; + } + + /// + /// If the given layer name is equal to the provided string, it clears it. + /// Used when a ZED layer is moved to a different layer. + /// + /// + /// + private void ClearLayerNameIfNeeded(int layer, string constname) + { + if (layer < 0 || layer > 31) return; //Invalid ID. + SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]); + SerializedProperty layerNames = tagManager.FindProperty("layers"); + if (layerNames.GetArrayElementAtIndex(layer).stringValue == constname) + { + layerNames.GetArrayElementAtIndex(layer).stringValue = ""; + tagManager.ApplyModifiedProperties(); + } + + + } + +} + + diff --git a/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs.meta b/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs.meta new file mode 100644 index 0000000..538cd0a --- /dev/null +++ b/Assets/ZED/Editor/Scripts/ZEDCameraEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4fe8b72cec5c83b4a8bcdffc6e193969 +timeCreated: 1543443416 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs b/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs new file mode 100644 index 0000000..4e29d56 --- /dev/null +++ b/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs @@ -0,0 +1,573 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; +using UnityEditor; +using System.Collections; + +/// +/// 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 +{ + /// + /// ZED unity logo + /// + static Texture2D image = null; + + private static EditorWindow window; + + private static bool showErrorMode = false; + private static bool showSettingsMode = false; + private static string errorMessage = ""; + + const bool forceSettingsShow = false; + bool showErrorPlugin = false; + + const string ignore = "ignore."; + const string useRecommended = "Use recommended ({0})"; + const string currentValue = " (current = {0})"; + + const string buildTarget = "Build Target"; + const string showUnitySplashScreen = "Show Unity Splashscreen"; + const string displayResolutionDialog = "Display Resolution Dialog"; + const string resizableWindow = "Resizable Window"; + const string colorSpace = "Color Space"; + const string gpuSkinning = "GPU Skinning"; + const string MSAAValue = "Anti Aliasing"; + const string runInBackground = "Run In Background"; + const string visibleInBackground = "Visible In Background"; + + + const BuildTarget needed_BuildTarget = BuildTarget.StandaloneWindows64; + const bool needed_ShowUnitySplashScreen = false; + const ResolutionDialogSetting needed_DisplayResolutionWindow = ResolutionDialogSetting.HiddenByDefault; + const bool needed_ResizableWindow = true; + const ColorSpace needed_ColorSpace = ColorSpace.Linear; + const bool needed_GPUSkinning = true; + const int needed_MSAAValue = 4; + const bool needed_RunInBackground = true; + const bool needed_VisibleInBackground = true; + static ZEDPluginInspector() + { + EditorApplication.update += OnInit; + } + + static void OnInit() + { + EditorApplication.update -= OnInit; + if (!EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isCompiling && !EditorApplication.isUpdating) { + if (!EditorPrefs.HasKey("ZED_NoWarning_Plugin")) + EditorApplication.update += UpdateWnd; + } + else + EditorApplication.update += UpdateLog; + + EditorApplication.update += UpdateSettingsWnd; + + } + + 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 + SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]); + SerializedProperty tagsProp = tagManager.FindProperty("tags"); + // Adding a Tag + string s = "HelpObject"; + + // Check if not here already + bool found = false; + for (int i = 0; i < tagsProp.arraySize; i++) + { + SerializedProperty t = tagsProp.GetArrayElementAtIndex(i); + 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 (!found) + { + tagsProp.InsertArrayElementAtIndex(0); + SerializedProperty n = tagsProp.GetArrayElementAtIndex(0); + n.stringValue = s; + } + + + // and to save the changes + tagManager.ApplyModifiedProperties(); + } + + static void UpdateLog() + { + if (!sl.ZEDCamera.CheckPlugin ()) { + Debug.Log ("ZED SDK is not installed or needs to be updated"); + } + + EditorApplication.update -= UpdateLog; + } + + + + static void UpdateSettingsWnd() + { + showSettingsMode = + (!EditorPrefs.HasKey(ignore + buildTarget) && + EditorUserBuildSettings.activeBuildTarget != needed_BuildTarget) || + (!EditorPrefs.HasKey(ignore + showUnitySplashScreen) && + PlayerSettings.SplashScreen.show != needed_ShowUnitySplashScreen) || + (!EditorPrefs.HasKey(ignore + displayResolutionDialog) && + PlayerSettings.displayResolutionDialog != needed_DisplayResolutionWindow) || + (!EditorPrefs.HasKey(ignore + resizableWindow) && + PlayerSettings.resizableWindow != needed_ResizableWindow) || + (!EditorPrefs.HasKey(ignore + colorSpace) && + PlayerSettings.colorSpace != needed_ColorSpace) || + (!EditorPrefs.HasKey(ignore + gpuSkinning) && + PlayerSettings.gpuSkinning != needed_GPUSkinning) || + (!EditorPrefs.HasKey(ignore + runInBackground) && + PlayerSettings.runInBackground != needed_RunInBackground) || + (!EditorPrefs.HasKey(ignore + visibleInBackground) && + PlayerSettings.visibleInBackground != needed_VisibleInBackground) || + (!EditorPrefs.HasKey(ignore + MSAAValue) && + QualitySettings.antiAliasing != needed_MSAAValue) || + forceSettingsShow; + + if (showSettingsMode) { + window = GetWindow (true); + window.maxSize = new Vector2 (400, 400); + window.minSize = window.maxSize; + window.Show (true); + } + + + EditorApplication.update -= UpdateSettingsWnd; + } + + static void UpdateWnd() + { + + if (!sl.ZEDCamera.CheckPlugin ()) { + errorMessage = ZEDLogMessage.Error2Str (ZEDLogMessage.ERROR.SDK_DEPENDENCIES_ISSUE); + showErrorMode = true; + window = GetWindow (true); + window.maxSize = new Vector2 (400, 600); + window.minSize = window.maxSize; + window.Show (true); + } + + EditorApplication.update -= UpdateWnd; + + } + + + + void OnGUI() + { + if (showErrorMode) { + showErrorWindow (); + } else if (showSettingsMode) { + showSettingsWindow(); + } + } + + /// + /// Displays a popup window when the correct ZED SDK version isn't installed. + /// + public void showErrorWindow() + { + if (image == null) { + image = Resources.Load ("Textures/logo", typeof(Texture2D)) as Texture2D; + + } + var rect = GUILayoutUtility.GetRect (position.width, 150, GUI.skin.box); + + if (image) { + GUI.DrawTexture (rect, image, ScaleMode.ScaleToFit); + } + GUIStyle myStyle = new GUIStyle (GUI.skin.label); + myStyle.normal.textColor = Color.red; + myStyle.fontStyle = FontStyle.Bold; + + GUILayout.Space (20); + GUILayout.BeginHorizontal (); + GUILayout.FlexibleSpace (); + GUILayout.Label ("ZED SDK is not installed or needs to be updated", myStyle); + GUILayout.FlexibleSpace (); + GUILayout.EndHorizontal (); + myStyle = new GUIStyle (GUI.skin.box); + myStyle.normal.textColor = Color.red; + + + GUI.Box (new Rect (0, position.height / 2, position.width, 100), errorMessage, myStyle); + + GUILayout.FlexibleSpace (); + GUILayout.BeginHorizontal (); + myStyle.normal.textColor = Color.black; + myStyle.fontStyle = FontStyle.Bold; + GUILayout.Label ("Do not ask me again..."); + showErrorPlugin = EditorGUILayout.Toggle ("",showErrorPlugin); + GUILayout.EndHorizontal (); + + + GUILayout.Space (10); + if (GUILayout.Button ("Close")) { + + if (showErrorPlugin) { + EditorPrefs.SetBool ("ZED_NoWarning_Plugin", true); + } + + this.Close (); + } + + + + + + } + + + 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) { + image = Resources.Load ("Textures/logo", typeof(Texture2D)) as Texture2D; + + } + var rect = GUILayoutUtility.GetRect (position.width, 150, GUI.skin.box); + + if (image) { + GUI.DrawTexture (rect, image, ScaleMode.ScaleToFit); + } + + EditorGUILayout.HelpBox("Recommended project settings for ZED Unity Plugin", MessageType.Warning); + + scrollPosition = GUILayout.BeginScrollView(scrollPosition); + + int numItems = 0; + + if (!EditorPrefs.HasKey(ignore + buildTarget) && + EditorUserBuildSettings.activeBuildTarget != needed_BuildTarget) + { + ++numItems; + + GUILayout.Label(buildTarget + string.Format(currentValue, EditorUserBuildSettings.activeBuildTarget)); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_BuildTarget))) + { + EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, needed_BuildTarget); + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + buildTarget, true); + } + + GUILayout.EndHorizontal(); + } + + if (!EditorPrefs.HasKey(ignore + showUnitySplashScreen) && + PlayerSettings.SplashScreen.show != needed_ShowUnitySplashScreen) + { + ++numItems; + + GUILayout.Label(showUnitySplashScreen + string.Format(currentValue, PlayerSettings.SplashScreen.show)); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_ShowUnitySplashScreen))) + { + PlayerSettings.SplashScreen.show = needed_ShowUnitySplashScreen; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + showUnitySplashScreen, true); + } + + GUILayout.EndHorizontal(); + } + + if (!EditorPrefs.HasKey(ignore + displayResolutionDialog) && + PlayerSettings.displayResolutionDialog != needed_DisplayResolutionWindow) + { + ++numItems; + + GUILayout.Label(displayResolutionDialog + string.Format(currentValue, PlayerSettings.displayResolutionDialog)); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_DisplayResolutionWindow))) + { + PlayerSettings.displayResolutionDialog = needed_DisplayResolutionWindow; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + displayResolutionDialog, true); + } + + GUILayout.EndHorizontal(); + } + + if (!EditorPrefs.HasKey(ignore + resizableWindow) && + PlayerSettings.resizableWindow != needed_ResizableWindow) + { + ++numItems; + + GUILayout.Label(resizableWindow + string.Format(currentValue, PlayerSettings.resizableWindow)); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_ResizableWindow))) + { + PlayerSettings.resizableWindow = needed_ResizableWindow; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + resizableWindow, true); + } + + GUILayout.EndHorizontal(); + } + + if (!EditorPrefs.HasKey(ignore + visibleInBackground) && + PlayerSettings.visibleInBackground != needed_VisibleInBackground) + { + ++numItems; + + GUILayout.Label(visibleInBackground + string.Format(currentValue, PlayerSettings.visibleInBackground)); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_VisibleInBackground))) + { + PlayerSettings.visibleInBackground = needed_VisibleInBackground; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + visibleInBackground, true); + } + + GUILayout.EndHorizontal(); + } + + if (!EditorPrefs.HasKey(ignore + runInBackground) && + PlayerSettings.runInBackground != needed_RunInBackground) + { + ++numItems; + + GUILayout.Label(runInBackground + string.Format(currentValue, PlayerSettings.runInBackground)); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_RunInBackground))) + { + PlayerSettings.runInBackground = needed_RunInBackground; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + runInBackground, true); + } + + GUILayout.EndHorizontal(); + } + + + if (!EditorPrefs.HasKey(ignore + gpuSkinning) && + PlayerSettings.gpuSkinning != needed_GPUSkinning) + { + ++numItems; + + GUILayout.Label(gpuSkinning + string.Format(currentValue, PlayerSettings.gpuSkinning)); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_GPUSkinning))) + { + PlayerSettings.gpuSkinning = needed_GPUSkinning; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + gpuSkinning, true); + } + + GUILayout.EndHorizontal(); + } + + if (!EditorPrefs.HasKey(ignore + colorSpace) && + PlayerSettings.colorSpace != needed_ColorSpace) + { + ++numItems; + + GUILayout.Label(colorSpace + string.Format(currentValue, PlayerSettings.colorSpace)); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_ColorSpace) + " - requires reloading scene")) + { + PlayerSettings.colorSpace = needed_ColorSpace; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + colorSpace, true); + } + + GUILayout.EndHorizontal(); + } + + + if (!EditorPrefs.HasKey(ignore + MSAAValue) && + QualitySettings.antiAliasing != needed_MSAAValue) + { + ++numItems; + + GUILayout.Label(MSAAValue + string.Format(currentValue, QualitySettings.antiAliasing)+"x Multi Sampling"); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(string.Format(useRecommended, needed_MSAAValue))) + { + QualitySettings.antiAliasing = needed_MSAAValue; + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Ignore")) + { + EditorPrefs.SetBool(ignore + MSAAValue, true); + } + + GUILayout.EndHorizontal(); + } + + + GUILayout.BeginHorizontal(); + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Clear All Ignores")) + { + EditorPrefs.DeleteKey(ignore + buildTarget); + EditorPrefs.DeleteKey(ignore + showUnitySplashScreen); + EditorPrefs.DeleteKey(ignore + displayResolutionDialog); + EditorPrefs.DeleteKey(ignore + resizableWindow); + EditorPrefs.DeleteKey(ignore + colorSpace); + EditorPrefs.DeleteKey(ignore + gpuSkinning); + EditorPrefs.DeleteKey(ignore + MSAAValue); + EditorPrefs.DeleteKey(ignore + visibleInBackground); + EditorPrefs.DeleteKey(ignore + runInBackground); + EditorPrefs.DeleteKey(ignore + MSAAValue); + + } + + + GUILayout.EndHorizontal(); + + GUILayout.EndScrollView(); + + GUILayout.FlexibleSpace(); + + GUILayout.BeginHorizontal(); + + if (numItems > 0) + { + if (GUILayout.Button("Accept All")) + { + // Only set those that have not been explicitly ignored. + if (!EditorPrefs.HasKey(ignore + buildTarget)) + EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, needed_BuildTarget); + if (!EditorPrefs.HasKey(ignore + showUnitySplashScreen)) + PlayerSettings.SplashScreen.show = needed_ShowUnitySplashScreen; + if (!EditorPrefs.HasKey(ignore + displayResolutionDialog)) + PlayerSettings.displayResolutionDialog = needed_DisplayResolutionWindow; + if (!EditorPrefs.HasKey(ignore + resizableWindow)) + PlayerSettings.resizableWindow = needed_ResizableWindow; + if (!EditorPrefs.HasKey(ignore + colorSpace)) + PlayerSettings.colorSpace = needed_ColorSpace; + if (!EditorPrefs.HasKey(ignore + gpuSkinning)) + PlayerSettings.gpuSkinning = needed_GPUSkinning; + if (!EditorPrefs.HasKey(ignore + runInBackground)) + PlayerSettings.runInBackground = needed_RunInBackground; + if (!EditorPrefs.HasKey(ignore + visibleInBackground)) + PlayerSettings.visibleInBackground = needed_VisibleInBackground; + if (!EditorPrefs.HasKey(ignore + MSAAValue)) + QualitySettings.antiAliasing = needed_MSAAValue; + + EditorUtility.DisplayDialog("Accept All", "Settings applied", "Ok"); + Close(); + } + + if (GUILayout.Button("Ignore All")) + { + if (EditorUtility.DisplayDialog("Ignore All", "Are you sure?", "Yes, Ignore All", "Cancel")) + { + // Only ignore those that do not currently match our recommended settings. + if (EditorUserBuildSettings.activeBuildTarget != needed_BuildTarget) + EditorPrefs.SetBool(ignore + buildTarget, true); + if (PlayerSettings.SplashScreen.show != needed_ShowUnitySplashScreen) + EditorPrefs.SetBool(ignore + showUnitySplashScreen, true); + if (PlayerSettings.displayResolutionDialog != needed_DisplayResolutionWindow) + EditorPrefs.SetBool(ignore + displayResolutionDialog, true); + if (PlayerSettings.resizableWindow != needed_ResizableWindow) + EditorPrefs.SetBool(ignore + resizableWindow, true); + if (PlayerSettings.colorSpace != needed_ColorSpace) + EditorPrefs.SetBool(ignore + colorSpace, true); + if (PlayerSettings.gpuSkinning != needed_GPUSkinning) + EditorPrefs.SetBool(ignore + gpuSkinning, true); + if (PlayerSettings.runInBackground != needed_RunInBackground) + EditorPrefs.SetBool(ignore + runInBackground, true); + if (PlayerSettings.visibleInBackground != needed_VisibleInBackground) + EditorPrefs.SetBool(ignore + visibleInBackground, true); + if (QualitySettings.antiAliasing != needed_MSAAValue) + EditorPrefs.SetBool(ignore + MSAAValue, true); + + Close(); + } + } + } + else if (GUILayout.Button("Close")) + { + Close(); + } + + GUILayout.EndHorizontal(); + } +} + diff --git a/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs.meta b/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs.meta new file mode 100644 index 0000000..5eea92d --- /dev/null +++ b/Assets/ZED/Editor/Scripts/ZEDPluginInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8af9b3322d52b024bb0c253c6eb8f12a +timeCreated: 1543443416 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Prefabs.meta b/Assets/ZED/Prefabs.meta new file mode 100644 index 0000000..f030606 --- /dev/null +++ b/Assets/ZED/Prefabs.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ac9734d4e18dbaa43ae7e922849c05ab +folderAsset: yes +timeCreated: 1488815750 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Prefabs/ZED_Rig_Mono.prefab b/Assets/ZED/Prefabs/ZED_Rig_Mono.prefab new file mode 100644 index 0000000..ff335bd --- /dev/null +++ b/Assets/ZED/Prefabs/ZED_Rig_Mono.prefab @@ -0,0 +1,293 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1180261165772202} + m_IsPrefabParent: 1 +--- !u!1 &1180261165772202 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4329734432191940} + - component: {fileID: 114491592745282986} + - component: {fileID: 114452247113840790} + m_Layer: 0 + m_Name: ZED_Rig_Mono + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1215292335019620 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4213858372801928} + - component: {fileID: 33108888876671232} + - component: {fileID: 23936732132281150} + - component: {fileID: 114589286496521468} + m_Layer: 0 + m_Name: Frame + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!1 &1795562263255876 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4476058232863476} + - component: {fileID: 20287226139793380} + - component: {fileID: 114177934168037988} + m_Layer: 0 + m_Name: Camera_Left + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4213858372801928 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1215292335019620} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 1} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4476058232863476} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4329734432191940 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1180261165772202} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4476058232863476} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4476058232863476 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1795562263255876} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4213858372801928} + m_Father: {fileID: 4329734432191940} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!20 &20287226139793380 +Camera: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1795562263255876} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 3 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: 1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 0 + m_HDR: 0 + m_AllowMSAA: 1 + m_ForceIntoRT: 0 + m_OcclusionCulling: 0 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 + m_StereoMirrorMode: 0 +--- !u!23 &23936732132281150 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1215292335019620} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_MotionVectors: 2 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 2100000, guid: 851b6eeee88b1e04c8a22454a27421a1, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &33108888876671232 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1215292335019620} + m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} +--- !u!114 &114177934168037988 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1795562263255876} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0e14eefa25813a3489cc8b38d2027ac8, type: 3} + m_Name: + m_EditorClassIdentifier: + canvas: {fileID: 1215292335019620} + viewMode: 0 + numberPointLights: 0 + numberSpotLights: 0 +--- !u!114 &114452247113840790 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1180261165772202} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7c602d2dc840f0144911c39c566846cb, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &114491592745282986 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1180261165772202} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 75b2a3ff7b847ca4490808f4c0432cd4, type: 3} + m_Name: + m_EditorClassIdentifier: + cameraID: 0 + depthMode: 1 + inputType: 0 + resolution: 2 + FPS: 60 + svoInputFileName: + svoLoopBack: 1 + svoRealTimeMode: 0 + currentFrame: 0 + numberFrameMax: 0 + pauseSVOReading: 0 + pauseLiveReading: 0 + NeedNewFrameGrab: 0 + streamInputIP: 127.0.0.1 + streamInputPort: 30000 + enableTracking: 1 + enableSpatialMemory: 1 + pathSpatialMemory: + estimateInitialPosition: 0 + mappingResolutionPreset: 1 + mappingRangePreset: 1 + isMappingFilteringEnable: 1 + isMappingTextured: 0 + saveMeshWhenOver: 0 + meshPath: Assets/ZEDMesh.obj + meshFilterParameters: 0 + depthOcclusion: 1 + postProcessing: 1 + m_cameraBrightness: 100 + m_maxDepthRange: 20 + svoOutputFileName: Assets/Recording.svo + svoOutputCompressionMode: 3 + needRecordFrame: 0 + enableStreaming: 0 + streamingCodec: 0 + streamingPort: 30000 + bitrate: 8000 + gopSize: -1 + adaptativeBitrate: 0 + fadeInOnStart: 1 + dontDestroyOnLoad: 0 + greySkybox: 1 + showarrig: 0 + cameraModel: '-' + cameraSerialNumber: '-' + cameraFirmware: '-' + versionZED: '-' + engineFPS: '-' + cameraFPS: '-' + HMDDevice: '-' + trackingState: '-' + gravityRotation: {x: 0, y: 0, z: 0, w: 1} + ZEDSyncPosition: {x: 0, y: 0, z: 0} + HMDSyncPosition: {x: 0, y: 0, z: 0} + ZEDSyncRotation: {x: 0, y: 0, z: 0, w: 0} + HMDSyncRotation: {x: 0, y: 0, z: 0, w: 0} + advancedPanelOpen: 0 + spatialMappingFoldoutOpen: 0 + recordingFoldoutOpen: 0 + streamingOutFoldoutOpen: 0 + camControlFoldoutOpen: 0 + arlayer: 30 + zedRigDisplayer: {fileID: 0} +--- !u!114 &114589286496521468 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1215292335019620} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 313514277d565454383ea4c1a1f8beb9, type: 3} + m_Name: + m_EditorClassIdentifier: + showInNonZEDCameras: 0 diff --git a/Assets/ZED/Prefabs/ZED_Rig_Mono.prefab.meta b/Assets/ZED/Prefabs/ZED_Rig_Mono.prefab.meta new file mode 100644 index 0000000..72e4c04 --- /dev/null +++ b/Assets/ZED/Prefabs/ZED_Rig_Mono.prefab.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 76db3eb81fd21ae45bab5204e324ae42 +timeCreated: 1498041047 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab b/Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab new file mode 100644 index 0000000..eeddb4d --- /dev/null +++ b/Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab @@ -0,0 +1,663 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1603769914748404} + m_IsPrefabParent: 1 +--- !u!1 &1082135366421468 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4795017531386668} + - component: {fileID: 20426257081025226} + - component: {fileID: 114025688240506870} + m_Layer: 0 + m_Name: Right_eye + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1175467483869550 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4327115905062700} + - component: {fileID: 20846656237544980} + - component: {fileID: 114495480594432558} + m_Layer: 0 + m_Name: Left_eye + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1352114948813630 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4138687653623062} + - component: {fileID: 81231073789856822} + - component: {fileID: 82354056950723132} + m_Layer: 0 + m_Name: Camera_eyes + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1386713500692820 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4552186382818458} + - component: {fileID: 33967978859279694} + - component: {fileID: 23931263026373856} + - component: {fileID: 114833973883948664} + m_Layer: 0 + m_Name: Frame + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1473301405527320 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4371821831063078} + - component: {fileID: 33507802862957374} + - component: {fileID: 23084009649085918} + - component: {fileID: 114346753093240460} + m_Layer: 0 + m_Name: Frame + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1603769914748404 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4309805032874704} + - component: {fileID: 114878768509821778} + - component: {fileID: 114711245158774928} + m_Layer: 0 + m_Name: ZED_Rig_Stereo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1721814514466412 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 4916666210046898} + - component: {fileID: 33546770458599288} + - component: {fileID: 65873696903358950} + - component: {fileID: 23993465884346736} + m_Layer: 0 + m_Name: Body + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &4138687653623062 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1352114948813630} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4327115905062700} + - {fileID: 4795017531386668} + - {fileID: 4916666210046898} + m_Father: {fileID: 4309805032874704} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4309805032874704 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1603769914748404} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4138687653623062} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4327115905062700 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1175467483869550} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4552186382818458} + m_Father: {fileID: 4138687653623062} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4371821831063078 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1473301405527320} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 1} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4795017531386668} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4552186382818458 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1386713500692820} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 1} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 4327115905062700} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4795017531386668 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1082135366421468} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4371821831063078} + m_Father: {fileID: 4138687653623062} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!4 &4916666210046898 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1721814514466412} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 1} + m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_Children: [] + m_Father: {fileID: 4138687653623062} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!20 &20426257081025226 +Camera: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1082135366421468} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.1 + far clip plane: 1000 + field of view: 56 + orthographic: 0 + orthographic size: 5 + m_Depth: -1.1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294964479 + m_RenderingPath: 1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 2 + m_HDR: 1 + m_AllowMSAA: 1 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 + m_StereoMirrorMode: 0 +--- !u!20 &20846656237544980 +Camera: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1175467483869550} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 2 + m_BackGroundColor: {r: 0, g: 0, b: 0, a: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.1 + far clip plane: 1000 + field of view: 56 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294963711 + m_RenderingPath: 1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 1 + m_HDR: 1 + m_AllowMSAA: 1 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 + m_StereoMirrorMode: 0 +--- !u!23 &23084009649085918 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1473301405527320} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_MotionVectors: 2 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 2100000, guid: 851b6eeee88b1e04c8a22454a27421a1, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!23 &23931263026373856 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1386713500692820} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 1 + m_MotionVectors: 2 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 2100000, guid: 851b6eeee88b1e04c8a22454a27421a1, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!23 &23993465884346736 +MeshRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1721814514466412} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &33507802862957374 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1473301405527320} + m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33546770458599288 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1721814514466412} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!33 &33967978859279694 +MeshFilter: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1386713500692820} + m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} +--- !u!65 &65873696903358950 +BoxCollider: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1721814514466412} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!81 &81231073789856822 +AudioListener: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1352114948813630} + m_Enabled: 1 +--- !u!82 &82354056950723132 +AudioSource: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1352114948813630} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 0} + m_PlayOnAwake: 1 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 2 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + - serializedVersion: 2 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 2 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 0 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 2 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 0 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 2 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 0 +--- !u!114 &114025688240506870 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1082135366421468} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0e14eefa25813a3489cc8b38d2027ac8, type: 3} + m_Name: + m_EditorClassIdentifier: + canvas: {fileID: 1473301405527320} + viewSide: 1 + viewMode: 0 + numberPointLights: 0 + numberSpotLights: 0 +--- !u!114 &114346753093240460 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1473301405527320} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 313514277d565454383ea4c1a1f8beb9, type: 3} + m_Name: + m_EditorClassIdentifier: + showInNonZEDCameras: 1 +--- !u!114 &114495480594432558 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1175467483869550} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0e14eefa25813a3489cc8b38d2027ac8, type: 3} + m_Name: + m_EditorClassIdentifier: + canvas: {fileID: 1386713500692820} + viewSide: 0 + viewMode: 0 + numberPointLights: 0 + numberSpotLights: 0 +--- !u!114 &114711245158774928 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1603769914748404} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 75b2a3ff7b847ca4490808f4c0432cd4, type: 3} + m_Name: + m_EditorClassIdentifier: + cameraID: 0 + depthMode: 1 + inputType: 0 + resolution: 2 + FPS: 60 + svoInputFileName: + svoLoopBack: 1 + svoRealTimeMode: 0 + currentFrame: 0 + numberFrameMax: 0 + pauseSVOReading: 0 + pauseLiveReading: 0 + NeedNewFrameGrab: 0 + streamInputIP: 127.0.0.1 + streamInputPort: 30000 + enableTracking: 1 + enableSpatialMemory: 1 + pathSpatialMemory: + estimateInitialPosition: 0 + mappingResolutionPreset: 1 + mappingRangePreset: 1 + isMappingFilteringEnable: 0 + isMappingTextured: 0 + saveMeshWhenOver: 0 + meshPath: Assets/ZEDMesh.obj + meshFilterParameters: 0 + depthOcclusion: 1 + postProcessing: 1 + m_cameraBrightness: 100 + m_maxDepthRange: 20 + svoOutputFileName: Assets/Recording.svo + svoOutputCompressionMode: 3 + needRecordFrame: 0 + enableStreaming: 0 + streamingCodec: 0 + streamingPort: 30000 + bitrate: 8000 + gopSize: -1 + adaptativeBitrate: 0 + fadeInOnStart: 1 + dontDestroyOnLoad: 0 + greySkybox: 1 + m_confidenceThreshold: 100 + showarrig: 0 + cameraModel: '-' + cameraSerialNumber: '-' + cameraFirmware: '-' + versionZED: '-' + engineFPS: '-' + cameraFPS: '-' + HMDDevice: '-' + trackingState: '-' + sensingMode: 1 + gravityRotation: {x: 0, y: 0, z: 0, w: 1} + ZEDSyncPosition: {x: 0, y: 0, z: 0} + HMDSyncPosition: {x: 0, y: 0, z: 0} + ZEDSyncRotation: {x: 0, y: 0, z: 0, w: 0} + HMDSyncRotation: {x: 0, y: 0, z: 0, w: 0} + advancedPanelOpen: 0 + spatialMappingFoldoutOpen: 0 + recordingFoldoutOpen: 0 + streamingOutFoldoutOpen: 0 + camControlFoldoutOpen: 1 + arlayer: 30 + zedRigDisplayer: {fileID: 0} +--- !u!114 &114833973883948664 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1386713500692820} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 313514277d565454383ea4c1a1f8beb9, type: 3} + m_Name: + m_EditorClassIdentifier: + showInNonZEDCameras: 1 +--- !u!114 &114878768509821778 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1603769914748404} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7c602d2dc840f0144911c39c566846cb, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab.meta b/Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab.meta new file mode 100644 index 0000000..04c0a9c --- /dev/null +++ b/Assets/ZED/Prefabs/ZED_Rig_Stereo.prefab.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e13ee7e0790c7d243b7aa67fe604acac +timeCreated: 1508143571 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK.meta b/Assets/ZED/SDK.meta new file mode 100644 index 0000000..a658f2a --- /dev/null +++ b/Assets/ZED/SDK.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f5d5003e172ac5b4f903e39fe5c95018 +folderAsset: yes +timeCreated: 1507557748 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers.meta b/Assets/ZED/SDK/Helpers.meta new file mode 100644 index 0000000..5d96a11 --- /dev/null +++ b/Assets/ZED/SDK/Helpers.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2141506e4c8dda44a9428e1e689511c7 +folderAsset: yes +timeCreated: 1507558379 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources.meta b/Assets/ZED/SDK/Helpers/Resources.meta new file mode 100644 index 0000000..d8a614a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 052fee6368ffcaf4a8aca699ad9b4831 +folderAsset: yes +timeCreated: 1507302069 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials.meta b/Assets/ZED/SDK/Helpers/Resources/Materials.meta new file mode 100644 index 0000000..14610ba --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 49ab59e2f00ddaf46b5770bd22667755 +folderAsset: yes +timeCreated: 1507710220 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/GUI.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI.meta new file mode 100644 index 0000000..c6d05a8 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7f8018d8e4efe3c41ba0742c1c7cd246 +folderAsset: yes +timeCreated: 1507730579 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_Fade.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_Fade.mat new file mode 100644 index 0000000..89f6b26 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_Fade.mat @@ -0,0 +1,77 @@ +%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: Mat_ZED_Fade + m_Shader: {fileID: 4800000, guid: 43bb64123ea14da43b05700aac6454e4, type: 3} + 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} + - _FadeColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_Fade.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_Fade.mat.meta new file mode 100644 index 0000000..91da366 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_Fade.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 00c0cf49a09a01642b7e3c4b889b25f8 +timeCreated: 1497361641 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_UITop.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_UITop.mat new file mode 100644 index 0000000..f267961 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_UITop.mat @@ -0,0 +1,83 @@ +%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: Mat_ZED_UITop + m_Shader: {fileID: 4800000, guid: 5858f212fb4e7c64180b7d9a541fc41f, type: 3} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 1 + 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 + - _ColorMask: 15 + - _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 + - _Stencil: 0 + - _StencilComp: 8 + - _StencilOp: 0 + - _StencilReadMask: 255 + - _StencilWriteMask: 148 + - _UVSec: 0 + - _UseUIAlphaClip: 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/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_UITop.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_UITop.mat.meta new file mode 100644 index 0000000..1c370e7 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/GUI/Mat_ZED_UITop.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2f69e3c5db673ac4bb12f553d1dcc24e +timeCreated: 1493218205 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: -1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting.meta new file mode 100644 index 0000000..a7f179c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d11d85f73aa948742a8220dcb3da5cb5 +folderAsset: yes +timeCreated: 1507730615 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred.mat new file mode 100644 index 0000000..9b068ae --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred.mat @@ -0,0 +1,40 @@ +%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: Mat_ZED_Deferred + m_Shader: {fileID: 4800000, guid: 9ed9dd24a1668264aa670d2bac004684, type: 3} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 1 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - : + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _CameraTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DepthXYZTex: + 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} + m_Floats: + - : 1 + m_Colors: + - : {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred.mat.meta new file mode 100644 index 0000000..ca5f836 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ef1a21d25d23a3f4690512c2d75a67a1 +timeCreated: 1490201219 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: -1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred_Lighting.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred_Lighting.mat new file mode 100644 index 0000000..c85a68a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred_Lighting.mat @@ -0,0 +1,88 @@ +%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: Mat_ZED_Deferred_Lighting + m_Shader: {fileID: 4800000, guid: fc101261ffd098d4182e59354a4e5e85, type: 3} + 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} + - _LightTexture0: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _LightTextureB0: + 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} + - _ShadowMapTexture: + 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/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred_Lighting.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred_Lighting.mat.meta new file mode 100644 index 0000000..58c1ba9 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Deferred_Lighting.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e9b21b07f1d69d846b0ce5efde2c42a5 +timeCreated: 1493719959 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward.mat new file mode 100644 index 0000000..bf710db --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward.mat @@ -0,0 +1,44 @@ +%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: Mat_ZED_Forward + m_Shader: {fileID: 4800000, guid: 4ab87418df3c64d4680282c62e272194, type: 3} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 1 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - : + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _CameraTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DepthXYZTex: + 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} + - _MaskTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - : 1 + m_Colors: + - : {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward.mat.meta new file mode 100644 index 0000000..77c3180 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a4099156e089e9146b1a4eb5c870ce56 +timeCreated: 1489659519 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: -1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward_Lighting.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward_Lighting.mat new file mode 100644 index 0000000..24a0521 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward_Lighting.mat @@ -0,0 +1,94 @@ +%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: Mat_ZED_Forward_Lighting + m_Shader: {fileID: 4800000, guid: 9a7011437ca03a24c8c5d45ccdf91e30, type: 3} + m_ShaderKeywords: DIRECTIONALLIGHTEFFECT_ON _EMISSION + m_LightmapFlags: 1 + 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} + - _CameraTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DepthXYZTex: + 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} + - _MaskTex: + 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} + - _ShadowMapTexture: + 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 + - _MaxDepth: 20 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + - directionalLightEffect: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward_Lighting.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward_Lighting.mat.meta new file mode 100644 index 0000000..86177b5 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Forward_Lighting.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 851b6eeee88b1e04c8a22454a27421a1 +timeCreated: 1485269531 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: -1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Hide.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Hide.mat new file mode 100644 index 0000000..88f2107 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Hide.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: Mat_ZED_Hide + m_Shader: {fileID: 4800000, guid: 9efc7125da4425d428044fc4c0d72ff7, type: 3} + 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/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Hide.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Hide.mat.meta new file mode 100644 index 0000000..cfd750f --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Lighting/Mat_ZED_Hide.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d3cc4ab8bb8b08649bd486af3dc7f689 +timeCreated: 1492502480 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection.meta new file mode 100644 index 0000000..25d7ea3 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e99170c889be0d249a6bfee0520384ed +folderAsset: yes +timeCreated: 1556222550 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane.mat new file mode 100644 index 0000000..4d0f2e7 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane.mat @@ -0,0 +1,87 @@ +%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: Mat_ZED_Geometry_WirePlane + m_Shader: {fileID: 4800000, guid: 0a38398fb6c3e8e4f82320212680ec72, type: 3} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _EMISSION _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 0 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _Bump: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _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: + - _Alpha: 1 + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _Gain: 1.5 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _Specular: 15 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _WireThickness: 18 + - _ZWrite: 0 + m_Colors: + - _BaseColor: {r: 0, g: 0.91724133, b: 1, a: 0.08} + - _Color: {r: 0, g: 0.747, b: 1, a: 0.422} + - _DiffuseColor: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 1, g: 1, b: 1, a: 1} + - _WireColor: {r: 0.86764705, g: 0.076557115, b: 0.5839459, a: 0.684} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane.mat.meta new file mode 100644 index 0000000..ad7b128 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c075616f3f471c14f9237aa9d8ef5a7b +timeCreated: 1521648099 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud.meta new file mode 100644 index 0000000..1f4a935 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a3356dd46d174364ca3ee309c42a7b1b +folderAsset: yes +timeCreated: 1507713031 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud/Mat_ZED_PointCloud.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud/Mat_ZED_PointCloud.mat new file mode 100644 index 0000000..3909a14 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud/Mat_ZED_PointCloud.mat @@ -0,0 +1,77 @@ +%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: Mat_ZED_PointCloud + m_Shader: {fileID: 4800000, guid: e559735f38c1ab04bb202a47093cfd4f, type: 3} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 1 + 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 + - _Size: 0.01 + - _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/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud/Mat_ZED_PointCloud.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud/Mat_ZED_PointCloud.mat.meta new file mode 100644 index 0000000..9df0c9d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PointCloud/Mat_ZED_PointCloud.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2de1863fc62ea7348a7813819b2c3573 +timeCreated: 1488185743 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: -1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing.meta new file mode 100644 index 0000000..a007319 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f0f9f02d5c68a3c4d874264789ae8840 +folderAsset: yes +timeCreated: 1507712958 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blit.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blit.mat new file mode 100644 index 0000000..3880df2 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blit.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: Mat_ZED_Blit + m_Shader: {fileID: 4800000, guid: 0e1a1e36ac2ada24ca19515d7e86836c, type: 3} + 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/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blit.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blit.mat.meta new file mode 100644 index 0000000..32dbf8a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blit.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 03161342bc5544849bea0803c778c5e1 +timeCreated: 1497516400 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blur.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blur.mat new file mode 100644 index 0000000..fde33b5 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blur.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: Mat_ZED_Blur + m_Shader: {fileID: 4800000, guid: ff7f942218f18e54d8ad8c85b234c74c, type: 3} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 1 + 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/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blur.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blur.mat.meta new file mode 100644 index 0000000..e490ce0 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Blur.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6a7ece4baaea8f24a9a21808bb3eacba +timeCreated: 1487762593 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: -1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_MaskCompositor.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_MaskCompositor.mat new file mode 100644 index 0000000..b73475b --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_MaskCompositor.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: Mat_ZED_MaskCompositor + m_Shader: {fileID: 4800000, guid: cbcdddda683f5cd4fba55830221ff820, type: 3} + 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/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_MaskCompositor.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_MaskCompositor.mat.meta new file mode 100644 index 0000000..33dea71 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_MaskCompositor.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d7bb14bcaa5d48a4bac7de222d43b075 +timeCreated: 1504261949 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_PostProcessing.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_PostProcessing.mat new file mode 100644 index 0000000..f23d3bc --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_PostProcessing.mat @@ -0,0 +1,77 @@ +%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: Mat_ZED_PostProcessing + m_Shader: {fileID: 4800000, guid: 3a59afe186bbfc84281b438294e4f41a, type: 3} + 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 + - _MinBlack: 0.01 + - _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/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_PostProcessing.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_PostProcessing.mat.meta new file mode 100644 index 0000000..6b1d41f --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_PostProcessing.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d66b181e9abec0e4ca7331c61952ec6e +timeCreated: 1493304484 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Stencil2Mask.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Stencil2Mask.mat new file mode 100644 index 0000000..5838c0d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Stencil2Mask.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: Mat_ZED_Stencil2Mask + m_Shader: {fileID: 4800000, guid: 9c1bda7cee8bf92488dfaf7a2963af2b, type: 3} + 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/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Stencil2Mask.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Stencil2Mask.mat.meta new file mode 100644 index 0000000..ddae806 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Stencil2Mask.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 52e5832abee9d3f40baffe96ff2c7fe5 +timeCreated: 1504252789 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Surface_PostProcessing.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Surface_PostProcessing.mat new file mode 100644 index 0000000..39241e5 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Surface_PostProcessing.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: Mat_ZED_Surface_PostProcessing + m_Shader: {fileID: 4800000, guid: f408df2c9d38f0a4788253fb1d9c106e, type: 3} + 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/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Surface_PostProcessing.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Surface_PostProcessing.mat.meta new file mode 100644 index 0000000..18aa02c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Surface_PostProcessing.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: dfb5c9589ed812b4aa5fc77e82cf8345 +timeCreated: 1509374688 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Unlit_PostProcessing.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Unlit_PostProcessing.mat new file mode 100644 index 0000000..518ab5b --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Unlit_PostProcessing.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: Mat_ZED_Unlit_PostProcessing + m_Shader: {fileID: 4800000, guid: 5efe839939b3d624b9bed96502a68c76, type: 3} + 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/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Unlit_PostProcessing.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Unlit_PostProcessing.mat.meta new file mode 100644 index 0000000..74fac30 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/PostProcessing/Mat_ZED_Unlit_PostProcessing.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 83e62a664f3d9974cb0d07cd7c52ff51 +timeCreated: 1509374659 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping.meta new file mode 100644 index 0000000..6a0476b --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 487ec056060620a4888f41f5520fda2a +folderAsset: yes +timeCreated: 1509117870 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe.mat new file mode 100644 index 0000000..008732b --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe.mat @@ -0,0 +1,87 @@ +%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: Mat_ZED_Geometry_Wireframe + m_Shader: {fileID: 4800000, guid: ff28f5e045891fc41ab0d0d9a402b51f, type: 3} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _EMISSION _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 0 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _Bump: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _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: + - _Alpha: 1 + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _Gain: 1.5 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _Specular: 15 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _WireThickness: 0 + - _ZWrite: 0 + m_Colors: + - _BaseColor: {r: 0, g: 0.91724133, b: 1, a: 0.08} + - _Color: {r: 0, g: 0.747, b: 1, a: 0.422} + - _DiffuseColor: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 1, g: 1, b: 1, a: 1} + - _WireColor: {r: 0.17254902, g: 0.6156863, b: 0.87058824, a: 0.684} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe.mat.meta new file mode 100644 index 0000000..96311c3 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bd72e0c92cbd1f14ca6810f4cfbfaabb +timeCreated: 1507191536 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_PostProcess_Blend.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_PostProcess_Blend.mat new file mode 100644 index 0000000..5bae0d2 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_PostProcess_Blend.mat @@ -0,0 +1,77 @@ +%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: Mat_ZED_PostProcess_Blend + m_Shader: {fileID: 4800000, guid: c5e2b5e6e2fe3274bbda6f48f9af188e, type: 3} + 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} + - _WireColor: {r: 0.17254902, g: 0.6156863, b: 0.87058824, a: 1} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_PostProcess_Blend.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_PostProcess_Blend.mat.meta new file mode 100644 index 0000000..f067dd7 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_PostProcess_Blend.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ac9fb22227b6d2e46bf891b6a64c97fe +timeCreated: 1492505149 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Texture.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Texture.mat new file mode 100644 index 0000000..e8eb846 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Texture.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: Mat_ZED_Texture + m_Shader: {fileID: 4800000, guid: bde3233f98eca534c877a46041c3801f, type: 3} + m_ShaderKeywords: _EMISSION + m_LightmapFlags: 1 + 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/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Texture.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Texture.mat.meta new file mode 100644 index 0000000..9b121fa --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Texture.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c787298985314f945a4a7c3d080cd89f +timeCreated: 1490888912 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: -1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay.mat new file mode 100644 index 0000000..3a05883 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay.mat @@ -0,0 +1,77 @@ +%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: Mat_ZED_Wireframe_Video_Overlay + m_Shader: {fileID: 4800000, guid: 332ca72ae3411344e82dcf92913f57dd, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + 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} + - _WireColor: {r: 0.17254902, g: 0.6156863, b: 0.87058824, a: 1} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay.mat.meta new file mode 100644 index 0000000..f2d5149 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay.mat.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 274cca6d7c9a5c0498aa8e144d3b06e2 +NativeFormatImporter: + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit.meta new file mode 100644 index 0000000..e772c38 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 09848456882466348b80587be77359ac +folderAsset: yes +timeCreated: 1507712947 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit.mat new file mode 100644 index 0000000..ec6126e --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit.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: Mat_ZED_Unlit + m_Shader: {fileID: 4800000, guid: e3ce76ae505317a40b8f52c2aac6fb9c, type: 3} + 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/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit.mat.meta new file mode 100644 index 0000000..1567c2d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2c8135c078212eb4d960bd36b9d8e9f5 +timeCreated: 1508144330 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit_BGRA.mat b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit_BGRA.mat new file mode 100644 index 0000000..234c246 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit_BGRA.mat @@ -0,0 +1,82 @@ +%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: Mat_ZED_Unlit_BGRA + m_Shader: {fileID: 4800000, guid: 22452c6b17a58c84cb92a9c44daee63f, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - : + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _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: + - : 1 + - _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: + - : {r: 1, g: 1, b: 1, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit_BGRA.mat.meta b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit_BGRA.mat.meta new file mode 100644 index 0000000..50bcb19 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/Materials/Unlit/Mat_ZED_Unlit_BGRA.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b09f48c1b07e9c7499e146e91844a0c7 +timeCreated: 1493743949 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI.meta new file mode 100644 index 0000000..cc35899 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d2e6c9d88565bae4eac33e374adeee73 +folderAsset: yes +timeCreated: 1498207260 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation.meta new file mode 100644 index 0000000..ceef462 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: de4a04ad4eebcaf448a267ac28526dc4 +folderAsset: yes +timeCreated: 1507279049 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation/Loading.anim b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation/Loading.anim new file mode 100644 index 0000000..26772d9 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation/Loading.anim @@ -0,0 +1,119 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Loading + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: [] + m_PPtrCurves: + - curve: + - time: 0 + value: {fileID: 21300000, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.033333335 + value: {fileID: 21300002, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.06666667 + value: {fileID: 21300004, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.1 + value: {fileID: 21300006, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.13333334 + value: {fileID: 21300008, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.16666667 + value: {fileID: 21300010, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.2 + value: {fileID: 21300012, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.23333333 + value: {fileID: 21300014, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.26666668 + value: {fileID: 21300016, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.3 + value: {fileID: 21300018, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.33333334 + value: {fileID: 21300020, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.36666667 + value: {fileID: 21300022, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.4 + value: {fileID: 21300024, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.43333334 + value: {fileID: 21300026, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.46666667 + value: {fileID: 21300028, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.5 + value: {fileID: 21300030, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.53333336 + value: {fileID: 21300032, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - time: 0.56666666 + value: {fileID: 21300034, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + attribute: m_Sprite + path: + classID: 114 + script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_SampleRate: 30 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 2015549526 + script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 1 + pptrCurveMapping: + - {fileID: 21300000, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300002, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300004, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300006, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300008, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300010, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300012, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300014, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300016, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300018, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300020, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300022, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300024, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300026, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300028, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300030, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300032, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + - {fileID: 21300034, guid: 0817f360cef64d149abcb4a040781a8c, type: 3} + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 0.6 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 1 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: [] + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_GenerateMotionCurves: 0 + m_Events: [] diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation/Loading.anim.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation/Loading.anim.meta new file mode 100644 index 0000000..8897ec8 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Animation/Loading.anim.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b26056710412b6e4e8854195a0130c6b +timeCreated: 1507213700 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material.meta new file mode 100644 index 0000000..1766d4b --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 73e3aa894ea99aa4aaceba0082925a82 +folderAsset: yes +timeCreated: 1507279020 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlay.mat b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlay.mat new file mode 100644 index 0000000..c924643 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlay.mat @@ -0,0 +1,83 @@ +%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: GUIOverlay + m_Shader: {fileID: 4800000, guid: 851377a9b12acec4d92cdb3107a2ede1, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3001 + 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 + - _ColorMask: 15 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _OverrideColor: 0 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _Stencil: 0 + - _StencilComp: 0 + - _StencilOp: 2 + - _StencilReadMask: 255 + - _StencilWriteMask: 255 + - _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/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlay.mat.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlay.mat.meta new file mode 100644 index 0000000..4b8f2b6 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlay.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: afd7bbe71ea0d3b4fbbfdc3248fb0ff7 +timeCreated: 1496315326 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayCustom.mat b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayCustom.mat new file mode 100644 index 0000000..5973d24 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayCustom.mat @@ -0,0 +1,82 @@ +%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: GUIOverlayCustom + m_Shader: {fileID: 4800000, guid: 851377a9b12acec4d92cdb3107a2ede1, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3001 + 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 + - _ColorMask: 15 + - _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 + - _Stencil: 0 + - _StencilComp: 8 + - _StencilOp: 0 + - _StencilReadMask: 255 + - _StencilWriteMask: 255 + - _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/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayCustom.mat.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayCustom.mat.meta new file mode 100644 index 0000000..df43e9e --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayCustom.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6f99bc424f1cb464d959476d70adf626 +timeCreated: 1506614736 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayText.mat b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayText.mat new file mode 100644 index 0000000..da98ffa --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayText.mat @@ -0,0 +1,83 @@ +%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: GUIOverlayText + m_Shader: {fileID: 4800000, guid: 851377a9b12acec4d92cdb3107a2ede1, type: 3} + m_ShaderKeywords: _OVERRIDECOLOR_ON + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3001 + 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 + - _ColorMask: 15 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _OverrideColor: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _Stencil: 0 + - _StencilComp: 0 + - _StencilOp: 0 + - _StencilReadMask: 255 + - _StencilWriteMask: 255 + - _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/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayText.mat.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayText.mat.meta new file mode 100644 index 0000000..b3a7386 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Material/GUIOverlayText.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: acdbdcaaee8a9914ba663c6390c98a99 +timeCreated: 1496315326 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader.meta new file mode 100644 index 0000000..9d295d8 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e94e1baa696cb6141850c0a38a929d85 +folderAsset: yes +timeCreated: 1507279037 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader/OverlayCustom.shader b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader/OverlayCustom.shader new file mode 100644 index 0000000..7e25090 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader/OverlayCustom.shader @@ -0,0 +1,99 @@ +Shader "ZED/UI/OverlayCustom" +{ + Properties + { + [PerRendererData] _MainTex("Font Texture", 2D) = "white" {} + + _Color("Tint", Color) = (1,1,1,1) + + _StencilComp("Stencil Comparison", Float) = 8 + _Stencil("Stencil ID", Float) = 0 + _StencilOp("Stencil Operation", Float) = 0 + _StencilWriteMask("Stencil Write Mask", Float) = 255 + _StencilReadMask("Stencil Read Mask", Float) = 255 + + _ColorMask("Color Mask", Float) = 15 + [MaterialToggle] _OverrideColor("Override color", Int) = 0 + } + + SubShader + { + LOD 100 + + Tags + { + "Queue" = "Transparent" + "IgnoreProjector" = "True" + "RenderType" = "Transparent" + "PreviewType" = "Plane" + "CanUseSpriteAtlas" = "True" + } + + Stencil + { + Ref[_Stencil] + Comp[_StencilComp] + Pass[_StencilOp] + ReadMask[_StencilReadMask] + WriteMask[_StencilWriteMask] + } + + Cull Off + Lighting Off + ZWrite Off + ZTest Always + + Blend SrcAlpha OneMinusSrcAlpha + ColorMask[_ColorMask] + + Pass + { + CGPROGRAM +#pragma vertex vert +#pragma fragment frag +#include "UnityCG.cginc" +#include "UnityUI.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + float2 texcoord : TEXCOORD0; + float4 color : COLOR; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + half2 texcoord : TEXCOORD0; + fixed4 color : COLOR; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + fixed4 _Color; + fixed4 _TextureSampleAdd; + int _OverrideColor; + v2f vert(appdata_t v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); + o.color = v.color * _Color; +#ifdef UNITY_HALF_TEXEL_OFFSET + o.vertex.xy += (_ScreenParams.zw - 1.0)*float2(-1,1); +#endif + + return o; + } + + fixed4 frag(v2f i) : SV_Target + { + half4 color = (tex2D(_MainTex, i.texcoord) + _TextureSampleAdd) * i.color; + if (_OverrideColor == 1) color.rgb = _Color; + clip(color.a - 0.01); + return color; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader/OverlayCustom.shader.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader/OverlayCustom.shader.meta new file mode 100644 index 0000000..b057a3c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Shader/OverlayCustom.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 851377a9b12acec4d92cdb3107a2ede1 +timeCreated: 1506614658 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures.meta new file mode 100644 index 0000000..b327eb0 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: be0c38f99e61cf544a6a91abffb9d5f0 +folderAsset: yes +timeCreated: 1507279062 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading.meta new file mode 100644 index 0000000..e064813 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f4b87cea997750948991bb9237a249ba +folderAsset: yes +timeCreated: 1507205066 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/HelveticaNeue Medium.ttf b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/HelveticaNeue Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..373e545f72834fb440bcd8eac69c468da549b880 GIT binary patch literal 39656 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 Ix-l>U035&9;s5{u literal 0 HcmV?d00001 diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/HelveticaNeue Medium.ttf.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/HelveticaNeue Medium.ttf.meta new file mode 100644 index 0000000..66a7115 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/HelveticaNeue Medium.ttf.meta @@ -0,0 +1,21 @@ +fileFormatVersion: 2 +guid: f0347d4b40918f74aba41da870e47183 +timeCreated: 1507206039 +licenseType: Free +TrueTypeFontImporter: + serializedVersion: 4 + fontSize: 32 + forceTextureCase: -2 + characterSpacing: 0 + characterPadding: 1 + includeFontData: 1 + fontName: HelveticaNeue + fontNames: + - HelveticaNeue + fallbackFontReferences: [] + customCharacters: + fontRenderingMode: 0 + ascentCalculationMode: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Loading.anim b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Loading.anim new file mode 100644 index 0000000..ea6ac00 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Loading.anim @@ -0,0 +1,170 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Loading + serializedVersion: 6 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: [] + m_PPtrCurves: + - curve: + - time: 0 + value: {fileID: 21300000, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.04 + value: {fileID: 21300002, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.08 + value: {fileID: 21300004, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.12 + value: {fileID: 21300006, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.16 + value: {fileID: 21300008, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.2 + value: {fileID: 21300010, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.24 + value: {fileID: 21300012, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.28 + value: {fileID: 21300014, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.32 + value: {fileID: 21300016, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.36 + value: {fileID: 21300018, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.4 + value: {fileID: 21300020, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.44 + value: {fileID: 21300022, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.48 + value: {fileID: 21300024, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.52 + value: {fileID: 21300026, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.56 + value: {fileID: 21300028, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.6 + value: {fileID: 21300030, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.64 + value: {fileID: 21300032, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.68 + value: {fileID: 21300034, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.72 + value: {fileID: 21300036, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.76 + value: {fileID: 21300038, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.8 + value: {fileID: 21300040, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.84 + value: {fileID: 21300042, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.88 + value: {fileID: 21300044, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.92 + value: {fileID: 21300046, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 0.96 + value: {fileID: 21300048, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1 + value: {fileID: 21300050, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.04 + value: {fileID: 21300052, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.08 + value: {fileID: 21300054, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.12 + value: {fileID: 21300056, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.16 + value: {fileID: 21300058, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.2 + value: {fileID: 21300060, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.24 + value: {fileID: 21300062, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.28 + value: {fileID: 21300064, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.32 + value: {fileID: 21300066, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - time: 1.36 + value: {fileID: 21300068, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + attribute: m_Sprite + path: + classID: 114 + script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_SampleRate: 25 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 2015549526 + script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + typeID: 114 + customType: 0 + isPPtrCurve: 1 + pptrCurveMapping: + - {fileID: 21300000, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300002, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300004, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300006, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300008, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300010, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300012, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300014, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300016, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300018, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300020, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300022, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300024, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300026, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300028, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300030, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300032, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300034, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300036, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300038, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300040, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300042, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300044, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300046, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300048, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300050, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300052, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300054, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300056, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300058, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300060, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300062, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300064, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300066, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + - {fileID: 21300068, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1.4 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 1 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: [] + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_GenerateMotionCurves: 0 + m_Events: [] diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Loading.anim.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Loading.anim.meta new file mode 100644 index 0000000..d220853 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/Loading.anim.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b7f7ab31a5f824c4287bf329e0c153ca +timeCreated: 1507218179 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/LoadingSprite.png b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/LoadingSprite.png new file mode 100644 index 0000000000000000000000000000000000000000..d1d1e78da6c64b2c0413e39a7a566ac24d90078d GIT binary patch literal 9022383 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 +/// Stops an object from being drawn for cameras that shouldn't draw it, without the use of layers. +/// Used so that the left ZED eye doesn't see the right eye's canvas object, and vice versa, and for +/// cameras seeing frames from other rigs. +/// +/// These are attached to canvas object in ZED_Rig_Mono and ZED_Rig_Stereo prefabs, and +/// assigned to Quad objects in the (normally hidden) AR rig created by ZEDManager when in stereo AR mode. +/// + /// List of all cameras from the ZED plugin that should see exactly one frame object. + /// Effectively unused if showInNonZEDCameras is set to false. + /// + private static List zedCamList = new List(); + + /// + /// If true, the object will be visible to all cameras not in zedCamList, namely cameras + /// that aren't part of the ZED plugin. + /// + public bool showInNonZEDCameras = true; + + /// + /// The camera that is allowed to render this object. + /// + private Camera renderableCamera = null; + + /// + /// Renderer attached to this object. + /// + private Renderer rend; + + /// + /// Enabled state of the attached Renderer prior to Unity's rendering stage. + /// Used so that manually disabling the object's MeshRenderer won't be undone by this script. + /// + private bool lastRenderState = true; + + public void Awake() + { + rend = GetComponent(); + + Camera.onPreRender += PreRender; + Camera.onPostRender += PostRender; + } + + /// + /// Adds a camera to an internal static list of cameras that should see exactly one ZED frame/canvas object. + /// Also called automatically if you call SetRenderCamera as a backup. + /// + /// + public static void RegisterZEDCam(Camera cam) + { + if (!zedCamList.Contains(cam)) + zedCamList.Add(cam); + } + + /// + /// Assigns a camera to this object, making it the only camera of the registered cameras that can see it. + /// + /// + public void SetRenderCamera(Camera cam) + { + RegisterZEDCam(cam); //In case it's not registered yet, make sure it is. + renderableCamera = cam; + } + + /// + /// Turns the renderer on or off depending on whether it should be drawn. + /// Subscribed to Camera.onPreRender in Awake(), which is called anytime any camera starts rendering. + /// + /// + private void PreRender(Camera currentcam) + { + lastRenderState = rend.enabled; + if (!rend.enabled) return; //We weren't going to render this object anyway, so skip the rest of the logic. + + //If it's a Unity scene camera, always show it. + if (currentcam.name.ToLower().Contains("scenecamera")) //There are more robust ways of checking this, but they are expensive. + { + rend.enabled = true; + return; + } + + //Is it the renderable camera we assigned to this instance? + if (currentcam == renderableCamera) + { + rend.enabled = true; //Always render that camera, no matter what. + } + else if(zedCamList.Contains(currentcam)) //Is it included in the ZED cameras that should only see one of these objects? + { + rend.enabled = false; //Those cameras can only render one quad, and it's not this one. + } + else //If it's a camera not on the list, render depending on showInNonZEDCameras. + { + rend.enabled = showInNonZEDCameras; + } + + } + + /// + /// Sets the renderer's state to what it was before PreRender() messed with it. + /// Subscribed to Camera.onPostRender in Awake(), which is called anytime any camera finishes rendering. + /// + private void PostRender(Camera currentcam) + { + rend.enabled = lastRenderState; + } + + private void OnDestroy() + { + Camera.onPreRender -= PreRender; + Camera.onPostRender -= PostRender; + } + +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display/HideFromWrongCameras.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Display/HideFromWrongCameras.cs.meta new file mode 100644 index 0000000..7e87e9f --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display/HideFromWrongCameras.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 313514277d565454383ea4c1a1f8beb9 +timeCreated: 1553809816 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs new file mode 100644 index 0000000..42b36df --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs @@ -0,0 +1,243 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; + +/// +/// 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 +{ + /// + /// 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 equal to the width * height of the ZED's resolution (eg. 1280 * 720). + /// + private int numberPoints = 0; + + /// + /// Instance of the ZEDManager interface + /// + public ZEDManager zedManager = null; + + /// + /// zed Camera controller by zedManager + /// + private sl.ZEDCamera zed = null; + + /// + /// Texture that holds the 3D position of the points. + /// + private Texture2D XYZTexture; + + /// + /// Texture that holds the colors of each point. + /// + private Texture2D colorTexture; + + /// + /// Temporary copy/buffer of the XYZTexture to stop the point cloud in a defined moment. + /// + private RenderTexture XYZTextureCopy = null; + + /// + /// 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. Usually Mat_ZED_PointCloud. + /// + private Material mat; + + /// + /// Cached property index of _Position shader property, so we only look it up once. Do not use. + /// + private static int? _positionid; + /// + /// Returns the property index of the _Position property, and looks it up if it hasn't been looked up yet. + /// + private static int positionID + { + get + { + if (_positionid == null) + { + _positionid = Shader.PropertyToID("_Position"); + } + return (int)_positionid; + } + } + /// + /// Cached property index of the _ColorTex shader property, so we only look it up once. Use colorTexID instead. + /// + private static int? _colortexid; + /// + /// Returns the property index of the _ColorTex property, which is the RGB color texture from the ZED. + /// + private static int colorTexID + { + get + { + if (_colortexid == null) + { + _colortexid = Shader.PropertyToID("_ColorTex"); + } + return (int)_colortexid; + } + } + /// + /// Cached property index of _XYZTex shader property, so we only look it up once. Use xyzTexID instead. + /// + private static int? _xyztexid; + /// + /// Returns the property index of the _XYZTex property, which is the XYZ position of each pixel relative to the ZED. + /// + private static int xyzTexID + { + get + { + if (_xyztexid == null) + { + _xyztexid = Shader.PropertyToID("_XYZTex"); + } + return (int)_xyztexid; + } + } + + /// + /// Whether the point cloud should be visible or not. + /// + [Tooltip("Whether the point cloud should be visible or not. ")] + public bool display = true; + + /// + /// 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; + + /// + /// Flag to check if the update has changed state. + /// + private bool previousUpdate = true; + + void Start() + { + if(zedManager == null) + { + zedManager = FindObjectOfType(); + if(ZEDManager.GetInstances().Count > 1) //We chose a ZED arbitrarily, but there are multiple cams present. Warn the user. + { + Debug.Log("Warning: " + gameObject.name + "'s zedManager was not specified, so the first available ZEDManager instance was " + + "assigned. However, there are multiple ZEDManager's in the scene. It's recommended to specify which ZEDManager you want to " + + "use to display a point cloud."); + } + } + + if (zedManager != null) + zed = zedManager.zedCamera; + } + + // Update is called once per frame + void Update() + { + if (zed.IsCameraReady) //Don't do anything unless the ZED has been initialized. + { + if (numberPoints == 0) + { + //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 material properties. + mat = new Material(Resources.Load("Materials/PointCloud/Mat_ZED_PointCloud") as Material); + if (mat != null) + { + //mat.SetTexture("_XYZTex", XYZTexture); + mat.SetTexture(xyzTexID, XYZTexture); + //mat.SetTexture("_ColorTex", colorTexture); + mat.SetTexture(colorTexID, colorTexture); + + } + } + + //If stop updated, create new render texture and fill them with the textures from the ZED. + // These textures will be displayed as they are not updated + if (!update && previousUpdate != update) + { + if (XYZTextureCopy == null) + { + XYZTextureCopy = new RenderTexture(XYZTexture.width, XYZTexture.height, 0, RenderTextureFormat.ARGBFloat); + } + + if (ColorTextureCopy == null) + { + 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); + + if (mat != null) + { + //mat.SetTexture("_XYZTex", XYZTextureCopy); + mat.SetTexture(xyzTexID, XYZTextureCopy); + //mat.SetTexture("_ColorTex", ColorTextureCopy); + mat.SetTexture(colorTexID, ColorTextureCopy); + } + } + //Send the textures to the material/shader. + if (update && previousUpdate != update && mat != null) + { + //mat.SetTexture("_XYZTex", XYZTexture); + mat.SetTexture(xyzTexID, XYZTexture); + //mat.SetTexture("_ColorTex", colorTexture); + mat.SetTexture(colorTexID, colorTexture); + + + } + previousUpdate = update; + } + } + + + void OnApplicationQuit() + { + //Free up memory. + mat = null; + if (XYZTextureCopy != null) + { + XYZTextureCopy.Release(); + } + + if (ColorTextureCopy != null) + { + ColorTextureCopy.Release(); + } + } + + void OnRenderObject() + { + if (mat != null) + { + if (hiddenObjectFromCamera == Camera.current) return; + + if (!display) return; //Don't draw anything if the user doesn't want to. + + //mat.SetMatrix("_Position", transform.localToWorldMatrix); + mat.SetMatrix(positionID, transform.localToWorldMatrix); + mat.SetPass(0); + Graphics.DrawProceduralNow(MeshTopology.Points, 1, numberPoints); + } + } + +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs.meta new file mode 100644 index 0000000..c7fad8a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPointCloudManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3cfa258225c336041996fa4a1792d6e3 +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs new file mode 100644 index 0000000..2b88999 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs @@ -0,0 +1,242 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; +using UnityEngine.Rendering; +/// +/// 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 +{ + /// + /// Cached property ID for _horizontal. Use horizontalPropertyID property instead. + /// + private static int? _horizpropID; + /// + /// Cached shader ID for "_horizontal" property, to optimize shader assignment. + /// We do this since this is a property we may set every frame. + /// + private static int horizontalPropertyID + { + get + { + if (_horizpropID == null) + { + _horizpropID = Shader.PropertyToID("horizontal"); + } + return (int)_horizpropID; + } + } + + /// + /// Returns the gaussian value for f(x) = (1/2*3.14*s)*e(-x*x/(2*s)). + /// + /// + /// + /// + public static float Gaussian(float x, float sigma) + { + return (1.0f / (2.0f * Mathf.PI * sigma)) * Mathf.Exp(-((x * x) / (2.0f * sigma))); + } + + /// + /// Computes weights to be sent to the blur shader. + /// + /// + /// + /// + public static void ComputeWeights(float sigma, out float[] weights_, out float[] offsets_) + { + float[] weights = new float[5]; + float[] offsets = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f }; + + weights_ = new float[5]; + offsets_ = new float[5] { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f }; + + // Calculate the weights + weights[0] = Gaussian(0, sigma); + if (sigma != 0) + { + float sum = weights[0]; + for (int i = 1; i < 5; ++i) + { + weights[i] = Gaussian(offsets[i], sigma); + sum += 2.0f * weights[i]; + } + + for (int i = 0; i < 5; ++i) + { + weights[i] /= sum; + } + + //Fix for just 3 fetches + weights_[0] = weights[0]; + weights_[1] = weights[1] + weights[2]; + weights_[2] = weights[3] + weights[4]; + + offsets_[0] = 0.0f; + offsets_[1] = ((weights[1] * offsets[1]) + (weights[2] * offsets[2])) / weights_[1]; + offsets_[2] = ((weights[3] * offsets[3]) + (weights[4] * offsets[4])) / weights_[2]; + } + } + + + + /// + /// Blurs a render texture. + /// + /// 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) + { + if (numberIterations == -1 || numberIterations == 0) + { + Graphics.Blit(source, dest, mat, pass); + return; + } + + RenderTexture buffer = RenderTexture.GetTemporary(source.width / downscale, source.height / downscale, source.depth, source.format, RenderTextureReadWrite.Default); + + if (mat == null) + { + Graphics.Blit(source, buffer); + Graphics.Blit(buffer, dest); + } + else + { + bool oddEven = false; + + //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. + for (int i = 0; i < numberIterations * 2; i++) + { + //mat.SetInt("horizontal", System.Convert.ToInt32(oddEven)); + mat.SetInt(horizontalPropertyID, System.Convert.ToInt32(oddEven)); + if (i < numberIterations * 2 - 1) + { + Graphics.Blit(oddEven ? buffer2 : buffer, !oddEven ? buffer2 : buffer, mat, pass); + oddEven = !oddEven; + } + else + { + //mat.SetInt("horizontal", System.Convert.ToInt32(oddEven)); + mat.SetInt(horizontalPropertyID, System.Convert.ToInt32(oddEven)); + + //Copy the buffer to the final texture. + if (oddEven) + { + Graphics.Blit(buffer2, dest, mat, pass); + } + else + { + Graphics.Blit(buffer, dest, mat, pass); + } + } + } + //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"); + internal static readonly int _TempRT = Shader.PropertyToID("_TempRT"); + internal static readonly int _TempRT2 = Shader.PropertyToID("_TempRT2"); + internal static readonly int _TempRT3 = Shader.PropertyToID("_TempRT3"); + + } + + /// + /// 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, 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) + { + + if (numberIterations == -1 || numberIterations == 0) + { + cb.GetTemporaryRT(Uniforms._TempRT, texture.width, texture.height, texture.depth); + cb.Blit(texture, Uniforms._TempRT, mat, pass); + cb.Blit(Uniforms._TempRT, texture); + cb.ReleaseTemporaryRT(Uniforms._TempRT); + return; + } + + cb.GetTemporaryRT(Uniforms._TempRT, texture.width / downscale, texture.height / downscale, texture.depth, FilterMode.Bilinear, texture.format, RenderTextureReadWrite.Default); + cb.GetTemporaryRT(Uniforms._TempRT2, texture.width / downscale, texture.height / downscale, texture.depth, FilterMode.Bilinear, texture.format, RenderTextureReadWrite.Default); + + 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++) + { + //mat.SetInt("horizontal", System.Convert.ToInt32(oddEven)); + mat.SetInt(horizontalPropertyID, System.Convert.ToInt32(oddEven)); + if (i < numberIterations * 2 - 1) + { + cb.Blit(oddEven ? Uniforms._TempRT2 : Uniforms._TempRT, !oddEven ? Uniforms._TempRT2 : Uniforms._TempRT, mat, pass); + oddEven = !oddEven; + } + else + { + //mat.SetInt("horizontal", System.Convert.ToInt32(oddEven)); + mat.SetInt(horizontalPropertyID, System.Convert.ToInt32(oddEven)); + + //Copy the buffer to the final texture + if (oddEven) + { + cb.Blit(Uniforms._TempRT2, texture, mat, pass); + } + else + { + cb.Blit(Uniforms._TempRT, texture, mat, pass); + } + } + } + //Destroy all the temporary buffers + cb.ReleaseTemporaryRT(Uniforms._TempRT); + cb.ReleaseTemporaryRT(Uniforms._TempRT2); + } + + public static void ComposeMask(CommandBuffer cb, RenderTexture mask, Material matStencilToMask, Material matComposeMask) + { + cb.GetTemporaryRT(Uniforms._TempRT, mask.width, mask.height, mask.depth, mask.filterMode, mask.format, RenderTextureReadWrite.Default); + cb.GetTemporaryRT(Uniforms._TempRT2, -1, -1, 24); + cb.Blit(mask, Uniforms._TempRT); + + //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. + cb.SetRenderTarget(Uniforms._TempRT2, BuiltinRenderTextureType.CurrentActive); + cb.Blit(BuiltinRenderTextureType.CameraTarget, Uniforms._TempRT2, matStencilToMask); + + //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); + cb.Blit(Uniforms._TempRT2, mask, matComposeMask); + } +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs.meta new file mode 100644 index 0000000..161d4fa --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDPostProcessingTools.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e10bd3a40c149eb4d89160fa8e7ae4e6 +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs new file mode 100644 index 0000000..8d0a43a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs @@ -0,0 +1,1475 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; +using UnityEngine.Rendering; + + +/// +/// 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. + /// + enum ZED_RENDERING_MODE + { + FORWARD, + DEFERRED, + LAST + }; + + /// + /// Which side of the camera (left/right) and whether or not this can be overridden by the camera's stereoTargetEye. + /// + public enum ZED_CAMERA_SIDE + { + /// + /// Feed from the ZED's left camera. Can be overridden by the camera's stereoTargetEye value. + /// + LEFT, + /// + /// Feed from the ZED's right camera. Can be overridden by the camera's stereoTargetEye value. + /// + RIGHT, + /// + /// Feed from the ZED's left camera. Won't be overridden. + /// + LEFT_FORCE, + /// + /// Feed from the ZED's right camera. Won't be overridden. + /// + RIGHT_FORCE + } + + /// + /// 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; + + /// + /// Which camera on the ZED the image/depth/etc. comes from. + /// If set to LEFT or RIGHT, this may be overridden by the camera's stereoTargetEye. + /// If set to LEFT_FORCE or RIGHT_FORCE, it will not be changed. + /// + [Tooltip("Which camera on the ZED the image/depth/etc. comes from.\r\n" + + "If set to LEFT or RIGHT, this may be overridden by the camera's stereoTargetEye.\r\n" + + "If set to LEFT_FORCE or RIGHT_FORCE, it will not be changed.")] + public ZED_CAMERA_SIDE viewSide = ZED_CAMERA_SIDE.LEFT; + + /// + /// The main material, set to the one on the canvas's MeshRenderer. Used to set the color and depth. + /// + private Material matRGB; + + /// + /// Aspect ratio of the textures. All the textures displayed should be in 16:9. + /// + private float aspect = 16.0f / 9.0f; + + /// + /// The Camera component representing an 'eye' of the ZED. Must be on the same GameObject as this component. + /// + private Camera cam; + + /// + /// zedCamera controlled by ZEDManager (one manager controls one camera) + /// + private sl.ZEDCamera zedCamera = null; + + /// + /// ZED Manager that controls the zed Camera + /// + private ZEDManager zedManager = null; + + + /// + /// 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. + /// Once created, the ZED SDK automatically updates it whenever the ZED captures new frames/images. + /// + Texture2D depth; + + /// + /// 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 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 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 used to get the shadows. Not needed for lighting otherwise. + /// + public Material forwardMat { get; private set; } + + /// + /// The material used to integrate the depth in deferred mode. Always used in deferred regardless of lighting/shadows. + /// + public Material deferredMat { get; private set; } + + /// + /// 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 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 for virtual lights on the real world. + /// Gets sent to the shader via a compute buffer. + /// + [SerializeField] + public struct PointLight + { + /// + /// The color, times the intensity. + /// + public Vector4 color; + /// + /// The range of the light. + /// + public float range; + /// + /// The position of the light. + /// + public Vector3 position; + } + /// + /// Maximum number of point lights accepted. + /// + const int NUMBER_POINT_LIGHT_MAX = 8; + + /// + /// 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]; + /// + /// The size, or 'stride', of each PointLight in bytes. Needed to construct computeBufferPointLight. + /// + const int SIZE_POINT_LIGHT_BYTES = 32; + + /// + /// Used to pass the pointLights array into matRGB's shader as a buffer. + /// + ComputeBuffer computeBufferPointLight; + + /// + /// Structure of the spotlight send to the shader + /// + [SerializeField] + public struct SpotLight + { + /// + /// The color, times the intensity. + /// + public Vector4 color; + /// + /// The position of the light. + /// + public Vector3 position; + /// + /// The light's normalized direction and angle. + /// + public Vector4 direction; + /// + /// The parameters for the light's falloff. + /// + public Vector4 parameters; + } + /// + /// 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; + + /// + /// 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. [0] is its direction and [1] is its color. + /// Only one directional light is allowed at once. + /// + private Vector4[] directionalLightData = new Vector4[2]; + + /// + /// Used to pass the spotLights array into matRGB's shader as a buffer. + /// + ComputeBuffer computeBufferSpotLight; + + //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; + + /// + /// Cached property id for _IsTextured. use isTexturedID property instead. + /// + private int? _istexturedid; + /// + /// Property id for _IsTextured, which is whether the rendered image has a texture overlay. + /// + private int isTexturedID + { + get + { + if (_istexturedid == null) _istexturedid = Shader.PropertyToID("_IsTextured"); + return (int)_istexturedid; + } + } + + /// + /// Cached property id for _Mask. use maskPropID property instead. + /// + private int? _maskpropid; + /// + /// Property id for _Mask, which is the RenderTexture property for an overlay texture. + /// + private int maskPropID + { + get + { + if (_maskpropid == null) _maskpropid = Shader.PropertyToID("_Mask"); + return (int)_maskpropid; + } + } + + /*** Post-process definitions***/ + + /// + /// The mask used for post-processing. Filled at runtime and updated each frame. + /// + private RenderTexture mask; + + /// + /// The post process material, used to add noise and change the color. + /// + private Material postprocessMaterial; + + /// + /// 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; + + /// + /// Used to blur the mask. + /// + private Material blurMaterial; + + /// + /// Used to load a source image's alpha channel into all channels of a destination image. + /// Used during post-processing. + /// + private Material blitMaterial; + + /// + /// Used to convert the stencil buffer of a rendertexture into a regular texture. + /// + private Material matStencilToMask; + + /// + /// Used to compose the virtual mask from different textures. + /// + private Material matComposeMask; + + /// + /// Used to blend the textures from ZEDMeshRenderer, when present. + /// This adds the wireframe effect seen from 3D scanning or plane detection. + /// + private Material blender; + + /// + /// 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; + + /// + /// Which side of the camera we render. Left = 0, Right ==1. + /// + private int side + { + get + { + if (viewSide == ZED_CAMERA_SIDE.LEFT || viewSide == ZED_CAMERA_SIDE.LEFT_FORCE) return 0; + else return 1; + } + } + + /// + /// 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; + + /// + /// The target RenderTexture we'll render to if in AR mode. + /// + [HideInInspector] + private RenderTexture renderTextureTarget; + public RenderTexture target + { + get { return renderTextureTarget; } + } + + void Awake() + { + //Get the current camera and set the aspect ratio. + zedManager = gameObject.transform.parent.GetComponent (); + cam = GetComponent(); + cam.aspect = aspect; + cam.renderingPath = RenderingPath.UsePlayerSettings; //Assigns the camera's rendering path to be consistent with the project's settings. + + //Make the canvas allow rendering this camera. + HideFromWrongCameras.RegisterZEDCam(cam); //Makes all objects with a HideFromWrongCamera hide from this, unless set to this specifc one. + HideFromWrongCameras hider = canvas.GetComponent(); + if(!hider) + { + hider = canvas.AddComponent(); + } + + hider.SetRenderCamera(cam); //This canvas will allow this camera to render it. + } + + /// + /// 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() + { + //Only do this if "Hide Skybox" is enabled in ZEDManager, which is is by default. + if (zedManager) + { + if (zedManager.greySkybox) + { + RenderSettings.skybox = null; + Color c; + ColorUtility.TryParseHtmlString("#999999", out c); + RenderSettings.ambientLight = c; + DynamicGI.UpdateEnvironment(); + } + } + } + + /// + /// Configures materials/values/settings needed for post-processing and displaying in proper aspect ratio. + /// + private void Start() + { + //No environmental lighting per default + Shader.SetGlobalFloat("_ZEDExposure", -1); + //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 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 effect. + float[] weights; + float[] offsets; + ZEDPostProcessingTools.ComputeWeights(0.3f, out weights, out offsets); + + //Set the blur config to the shader, should be constant + blurMaterial = new Material(Resources.Load("Materials/PostProcessing/Mat_ZED_Blur") as Material); + blurMaterial.SetFloatArray("weights", weights); + blurMaterial.SetFloatArray("offset", offsets); + //blurMaterial.SetTexture("_Mask", mask); + blurMaterial.SetTexture(maskPropID, mask); + + + //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); + UnityEditor.PlayerSettings.SetAspectRatio(UnityEditor.AspectRatio.Aspect4by3, false); + UnityEditor.PlayerSettings.SetAspectRatio(UnityEditor.AspectRatio.Aspect5by4, false); +#endif + CreateRenderTexture(); + + //Load the blender for the zedmesher + blender = new Material(Resources.Load("Materials/SpatialMapping/Mat_ZED_PostProcess_Blend") as Material); + + //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(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 fade-in effect for when the camera first becomes visible. + if (zedManager.fadeInOnStart) + gameObject.AddComponent(); + + //This cannot happen but just in case... + if (zedManager == null) + return; + + zedCamera = zedManager.zedCamera; + SetTextures(zedCamera,viewMode); + canvas.SetActive(true); + canvas.transform.SetParent (cam.transform); + ConfigureLightAndShadow(cam.actualRenderingPath); + + //Move the plane with the optical centers. + float plane_distance =0.15f; + Vector4 opticalCenters = zedCamera.ComputeOpticalCenterOffsets(plane_distance); + + if (side==0) + canvas.transform.localPosition = new Vector3(opticalCenters.x, -1.0f * opticalCenters.y,plane_distance); + else if (side==1) + canvas.transform.localPosition = new Vector3(opticalCenters.z, -1.0f * opticalCenters.w,plane_distance); + + + //Set the camera's parameters based on the ZED's, and scale the screen based on its distance. + if (zedCamera.IsCameraReady) + { + 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 //Just scale the screen. + { + 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(); + + meshCanvas = gameObject.transform.GetChild(0).GetComponent(); + canvas.SetActive(false); + + //iterate until we found the ZED Manager parent... + Transform ObjParent = gameObject.transform; + int tries = 0; + while (zedManager == null && tries<5) { + if (ObjParent!=null) + zedManager= ObjParent.GetComponent (); + if (zedManager == null && ObjParent!=null) + ObjParent = ObjParent.parent; + tries++; + } + + if (zedManager != null) { + zedManager.OnZEDReady += ZEDReady; + zedManager.OnZEDDisconnected += ZEDDisconnected; + } + } + + /// + /// Disables the canvas and unsubscribes from events from the ZED. + /// + private void OnDisable() + { + if (zedManager != null) { + zedManager.OnZEDReady -= ZEDReady; + zedManager.OnZEDDisconnected -= ZEDDisconnected; + } + canvas.SetActive(false); + } + + + /// + /// Invisible object used to force Unity to render a shadow map. + /// + GameObject forceShadowObject = null; + + /// + /// Configure the canvas to get and light and shadow. + /// + /// The current rendering path used + private void ConfigureLightAndShadow(RenderingPath renderingPath) + { + RenderingPath current = actualRenderingPath; + actualRenderingPath = renderingPath; + + if (renderingPath == RenderingPath.Forward) + { + canvas.SetActive(true); + SetForward(); + + } + else if (renderingPath == RenderingPath.DeferredShading) + { + SetDeferred(); + } + else //We're using an unknown rendering path. Log an error. + { + actualRenderingPath = current; + Debug.LogError(" [ ZED Plugin ] : The rendering path " + cam.actualRenderingPath.ToString() + " is not compatible with the ZED"); + } + } + + /// + /// Clear the depth buffer used. + /// Called when configuring this script for the given rendering path (forward or deferred). + /// + private void ClearDepthBuffers() + { + if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null) + { + buffer[(int)ZED_RENDERING_MODE.FORWARD].Dispose(); + buffer[(int)ZED_RENDERING_MODE.FORWARD] = null; + } + + if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) + { + buffer[(int)ZED_RENDERING_MODE.DEFERRED].Dispose(); + buffer[(int)ZED_RENDERING_MODE.DEFERRED] = null; + + } + } + + /// + /// Configure the materials and buffer for the forward rendering path. + /// + private void SetForward() + { + // cam.RemoveAllCommandBuffers (); + 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 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 that forces Unity to calculate shadows. + if (forceShadowObject == null) + { + ConfigureForceShadowObject(); + } + + //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. + if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null) + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + + if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) + cam.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); + + ClearDepthBuffers(); + + if (postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) + cam.RemoveCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]); + + if (postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) + { + postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED].Dispose(); + postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] = null; + } + + //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); + buffer[(int)ZED_RENDERING_MODE.FORWARD].DrawMesh(meshCanvas.mesh, gameObject.transform.GetChild(0).transform.localToWorldMatrix, forwardMat); + + if (mask == null || !mask.IsCreated()) + { + mask = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.R8); + } + + //Set up the post-processing material. + postprocessMaterial.SetTexture("ZEDMaskPostProcess", mask); + postprocessMaterial.SetTexture("ZEDTex", textureEye); + + postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] = new CommandBuffer(); + postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].name = "ZED_FORWARD_POSTPROCESS"; + postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].Blit(BuiltinRenderTextureType.CameraTarget, mask, blitMaterial, 0); + postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD].SetGlobalTexture("_ZEDMaskVirtual", mask); + + + 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 (computeBufferPointLight == null) + { + computeBufferPointLight = new ComputeBuffer(NUMBER_POINT_LIGHT_MAX, SIZE_POINT_LIGHT_BYTES); + computeBufferPointLight.SetData(pointLights); + + matRGB.SetBuffer("pointLights", computeBufferPointLight); + } + + if (computeBufferSpotLight == null) + { + computeBufferSpotLight = new ComputeBuffer(NUMBER_SPOT_LIGHT_MAX, SIZE_SPOT_LIGHT_BYTES); + computeBufferSpotLight.SetData(spotLights); + matRGB.SetBuffer("spotLights", computeBufferSpotLight); + } + + //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 rendering path. + /// + private void SetDeferred() + { + //Disable MSSA as it's not supported with deferred. +#if UNITY_5_6_OR_NEWER + 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. + 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", cam.projectionMatrix); + + deferredMat.SetTexture("_MainTex", textureEye); + deferredMat.SetTexture("_DepthXYZTex", depth); + deferredMat.SetTexture("_NormalsTex", normals); + + + //Clear the buffers. + if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null) + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + + if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) + cam.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); + + if (postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] != null) + 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(); + postProcessBuffer[(int)ZED_RENDERING_MODE.FORWARD] = null; + } + + ClearDepthBuffers(); + + //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 (cam.allowHDR) + { + RenderTargetIdentifier[] mrt = { BuiltinRenderTextureType.GBuffer0, BuiltinRenderTextureType.GBuffer1, BuiltinRenderTextureType.GBuffer2, BuiltinRenderTextureType.CameraTarget }; + buffer[(int)ZED_RENDERING_MODE.DEFERRED].SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget); + } + else + { + RenderTargetIdentifier[] mrt = { BuiltinRenderTextureType.GBuffer0, BuiltinRenderTextureType.GBuffer1, BuiltinRenderTextureType.GBuffer2, BuiltinRenderTextureType.GBuffer3 }; + buffer[(int)ZED_RENDERING_MODE.DEFERRED].SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget); + } + buffer[(int)ZED_RENDERING_MODE.DEFERRED].DrawMesh(meshCanvas.mesh, gameObject.transform.GetChild(0).transform.localToWorldMatrix, deferredMat); + + if (mask == null || !mask.IsCreated()) + { + mask = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.R8); + } + //Set the post process buffer + postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] = new CommandBuffer(); + postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED].name = "ZED_FORWARD_POSTPROCESS"; + postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED].Blit(BuiltinRenderTextureType.GBuffer0, mask, blitMaterial, 0); + postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED].SetGlobalTexture("_ZEDMaskVirtual", mask); + postprocessMaterial.SetTexture("ZEDMaskPostProcess", mask); + postprocessMaterial.SetTexture("ZEDTex", textureEye); + + + + 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) + { + ConfigureForceShadowObject(); + } + transform.GetChild(0).GetComponent().enabled = false; + + } + + /// + /// 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, cam.nearClipPlane); + forceShadowObject.GetComponent().sharedMaterial = Resources.Load("Materials/Lighting/Mat_ZED_Hide") as Material; + Destroy(forceShadowObject.GetComponent()); + forceShadowObject.hideFlags = HideFlags.HideInHierarchy; + } + + /// + /// 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 (cam.stereoTargetEye != StereoTargetEyeMask.None && zedManager.IsStereoRig == true) + { + if (zedCamera != null && zedCamera.IsCameraReady) + { + renderTextureTarget = new RenderTexture(zedCamera.ImageWidth, zedCamera.ImageHeight, 24, RenderTextureFormat.ARGB32); + cam.targetTexture = renderTextureTarget; + } + else if(sl.ZEDCamera.CheckPlugin()) + { + renderTextureTarget = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32); + cam.targetTexture = renderTextureTarget; + } + } + } + + /// + /// 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) + { + float baseline = zedCamera.Baseline; + canvas.transform.localRotation = Quaternion.identity; + canvas.transform.localPosition = new Vector3(0, 0, 0); + + if(zedManager.IsStereoRig == true && cam.stereoTargetEye != StereoTargetEyeMask.None) + { + if (zedCamera != null && zedCamera.IsCameraReady) + { + renderTextureTarget = new RenderTexture(zedCamera.ImageWidth, zedCamera.ImageHeight, 24, RenderTextureFormat.ARGB32); + cam.targetTexture = renderTextureTarget; + } + + //Set the camera to match the target stereo eye, unless force otherwise. + switch(cam.stereoTargetEye) + { + case StereoTargetEyeMask.Left: + if (viewSide == ZED_CAMERA_SIDE.RIGHT) viewSide = ZED_CAMERA_SIDE.LEFT; + break; + case StereoTargetEyeMask.Right: + if (viewSide == ZED_CAMERA_SIDE.LEFT) viewSide = ZED_CAMERA_SIDE.RIGHT; + break; + default: + break; + } + } + + switch (viewSide) //Set up textures from the left camera or right camera, depending. + { + case ZED_CAMERA_SIDE.LEFT: + case ZED_CAMERA_SIDE.LEFT_FORCE: + default: + switch (view_mode) //Which kind of texture we view. + { + case sl.VIEW_MODE.VIEW_IMAGE: + textureEye = zedCamera.CreateTextureImageType(sl.VIEW.LEFT); + break; + case sl.VIEW_MODE.VIEW_DEPTH: + textureEye = zedCamera.CreateTextureImageType(sl.VIEW.DEPTH); + break; + case sl.VIEW_MODE.VIEW_NORMALS: + textureEye = zedCamera.CreateTextureImageType(sl.VIEW.NORMALS); + break; + } + normals = zedCamera.CreateTextureMeasureType(sl.MEASURE.NORMALS, resolution); + depth = zedCamera.CreateTextureMeasureType(sl.MEASURE.DEPTH, resolution); + break; + case ZED_CAMERA_SIDE.RIGHT: + case ZED_CAMERA_SIDE.RIGHT_FORCE: + switch (view_mode)//Which kind of texture we view. + { + case sl.VIEW_MODE.VIEW_IMAGE: + textureEye = zedCamera.CreateTextureImageType(sl.VIEW.RIGHT); + break; + case sl.VIEW_MODE.VIEW_DEPTH: + textureEye = zedCamera.CreateTextureImageType(sl.VIEW.DEPTH_RIGHT); + break; + case sl.VIEW_MODE.VIEW_NORMALS: + textureEye = zedCamera.CreateTextureImageType(sl.VIEW.NORMALS_RIGHT); + break; + } + normals = zedCamera.CreateTextureMeasureType(sl.MEASURE.NORMALS_RIGHT, resolution); + depth = zedCamera.CreateTextureMeasureType(sl.MEASURE.DEPTH_RIGHT, resolution); + break; + } + } + + /// + /// 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) + { + if (forwardMat) + { + if (enable) + { + forwardMat.EnableKeyword(name); + } + else + { + forwardMat.DisableKeyword(name); + } + return true; + + } + + return false; + } + + /// + /// 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) + { + if (enable) + { + deferredMat.EnableKeyword(name); + } + else + { + deferredMat.DisableKeyword(name); + } + return true; + + } + + return false; + } + + /// + /// 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) + { + if (enable) + { + matRGB.EnableKeyword(name); + } + else + { + matRGB.DisableKeyword(name); + } + return true; + + } + + return false; + } + + + //Variables to get information 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; + + /// + /// Updates lighting information, packages them into ComputeBuffers and sends them to the shader. + /// + void UpdateLights() + { + bool hasShadows = false; + + int pointLightIndex = 0; + int spotLightIndex = 0; + bounds.center = transform.position; + + foreach (ZEDLight zed_light in ZEDLight.s_lights) + { + Light light = zed_light.cachedLight; + + if (light.type == LightType.Directional || Vector3.Distance(bounds.center, light.transform.position) < (light.range + bounds.extents.x)) + { + + //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 + spotLightIndex) < NUMBER_LIGHTS_MAX || light.type == LightType.Directional)) + { + if (light.type == LightType.Point) + { + + if (pointLightIndex < NUMBER_POINT_LIGHT_MAX) + { + pointLights[pointLightIndex].color = light.color * light.intensity; + pointLights[pointLightIndex].position = light.gameObject.transform.position; + pointLights[pointLightIndex].range = light.range; + + pointLightIndex++; + } + + } + + else if (light.type == LightType.Spot) + { + + if (spotLightIndex < NUMBER_SPOT_LIGHT_MAX) + { + 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) + { + 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. + 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. + if (light.commandBufferCount == 0) + { + CommandBuffer lightBuffer = new CommandBuffer(); + lightBuffer.name = "ZED_Copy_ShadowMap"; + lightBuffer.SetGlobalTexture("_DirectionalShadowMap", BuiltinRenderTextureType.CurrentActive); + + light.AddCommandBuffer(LightEvent.AfterScreenspaceMask, lightBuffer); + } + + } + } + } + } + } + //Send the new light data to the final display material. + if (computeBufferPointLight != null) + { + computeBufferPointLight.SetData(pointLights); + } + if (computeBufferSpotLight != null) + { + computeBufferSpotLight.SetData(spotLights); + } + + numberPointLights = pointLightIndex; + numberSpotLights = spotLightIndex; + + if (matRGB != null) + { + //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)); + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + if (hasShadows) + { + cam.AddCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + } + + } + //Send the number of point lights/spotlights to the shader. + matRGB.SetInt(numberPointLightsID, pointLightIndex); + matRGB.SetInt(numberSpotLightsID, spotLightIndex); + } + matRGB.SetVectorArray("ZED_directionalLight", directionalLightData); + } + + + /// + /// 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; + } + + /// + /// 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; + screen.transform.localScale = new Vector3((height*aspect), height, 1); + } + + private void scaleXY(GameObject screen, float fovH,float fovV) + { + float height = Mathf.Tan(0.5f * fovV) * Vector3.Distance(screen.transform.localPosition, Vector3.zero) * 2; + float width = Mathf.Tan(0.5f * fovH) * Vector3.Distance(screen.transform.localPosition,Vector3.zero) * 2; + screen.transform.localScale = new Vector3(width, height, 1); + } + + public void Clear() + { + + if (buffer[(int)ZED_RENDERING_MODE.FORWARD] != null) + cam.RemoveCommandBuffer(CameraEvent.BeforeDepthTexture, buffer[(int)ZED_RENDERING_MODE.FORWARD]); + + if (buffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) + cam.RemoveCommandBuffer(CameraEvent.AfterGBuffer, buffer[(int)ZED_RENDERING_MODE.DEFERRED]); + + if (postProcessBuffer [(int)ZED_RENDERING_MODE.FORWARD] != null) + cam.RemoveCommandBuffer (CameraEvent.AfterForwardAlpha, postProcessBuffer [(int)ZED_RENDERING_MODE.FORWARD]); + + if (postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED] != null) + cam.RemoveCommandBuffer(CameraEvent.AfterFinalPass, postProcessBuffer[(int)ZED_RENDERING_MODE.DEFERRED]); + + + ClearDepthBuffers(); + + } + + void OnApplicationQuit() + { + if (computeBufferPointLight != null) + { + computeBufferPointLight.Release(); + } + + if (computeBufferSpotLight != null) + { + computeBufferSpotLight.Release(); + } + + if (mask != null) + { + mask.Release(); + } + } + + /// + /// Updates the output size to fit the window at 16:9 and the bounds for light filtering, and calculates the lighting. + /// + void Update() + { + if (zedManager == null) + return; + + if(aspectRatio != null) + { + aspectRatio.Update(); + } + + if (actualRenderingPath == RenderingPath.Forward) + { + bounds.center = transform.position; + UpdateLights(); + } + + if(zedManager.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 && cam.actualRenderingPath != actualRenderingPath) + { + ConfigureLightAndShadow(cam.actualRenderingPath); + } +#endif + + + } + + /// + /// 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; + blender.SetTexture("_ZEDMeshTex", textureMapping); + } + + /// + /// Where the post-processing occurs. + /// Called by Unity whenever the attached Camera renders an image. + /// + /// + /// + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (zedManager.GetSpatialMapping.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 (isTexturedID, 0); + + Graphics.Blit (tmpSource, destination, blender); + RenderTexture.ReleaseTemporary (tmpSource); + } + else + { + if (ARpostProcessing && mask != null && zedCamera.IsCameraReady) //Apply post-processing, if enabled. + { + + if (actualRenderingPath == RenderingPath.DeferredShading) + { + + RenderTexture bluredMask = RenderTexture.GetTemporary(mask.width, mask.height, mask.depth, mask.format); + RenderTexture buffer = RenderTexture.GetTemporary(source.width, source.height, 24); + + Graphics.SetRenderTarget(buffer); + GL.Clear(false, true, new Color(0, 0, 0, 0)); // clear the full RT + + //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 retrieved in the forward pass. The shader should set the stencil to 148. + Graphics.Blit(mask, bluredMask); + //matComposeMask.SetTexture("_Mask", bluredMask); + matComposeMask.SetTexture(maskPropID, bluredMask); + Graphics.Blit(buffer, mask, matComposeMask); + + ApplyPostProcess(source, destination, bluredMask); + + RenderTexture.ReleaseTemporary(buffer); + RenderTexture.ReleaseTemporary(bluredMask); + } + else //Forward path. + { + RenderTexture bluredMask = RenderTexture.GetTemporary(mask.width, mask.height, mask.depth, mask.format); + ApplyPostProcess(source, destination, bluredMask); + RenderTexture.ReleaseTemporary(bluredMask); + } + } + else //Not using post-processing. + { + Graphics.Blit(source, destination); + } + } + } + + /// + /// 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); + + Graphics.Blit(source, tempDestination, postprocessMaterial); + ZEDPostProcessingTools.Blur(mask, bluredMask, blurMaterial, 3, 1, 1); + + //blurMaterial.SetTexture("_Mask", bluredMask); + blurMaterial.SetTexture(maskPropID, bluredMask); + ZEDPostProcessingTools.Blur(tempDestination, destination, blurMaterial, 2, 1, 1); + mask.SetGlobalShaderProperty("_ZEDMaskVirtual"); + RenderTexture.ReleaseTemporary(tempDestination); + + } + + /// + /// 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. + /// + private int ScreenSizeX = 0; + + /// + /// Current screen height. + /// + private int ScreenSizeY = 0; + + /// + /// Camera to set to 16:9. + /// + private Camera cam; + + /// + /// Aspect ratio targeted. + /// + private const float TARGET_ASPECT = 16.0f / 9.0f; + + + public WindowAspectRatio(Camera camera) + { + cam = camera; + RescaleCamera(); + CreateCamera(); + } + + /// + /// Create a custom hidden camera to render black bars in the background. + /// + /// + private GameObject CreateCamera() + { + GameObject o = new GameObject("CameraBlackBackground"); + Camera cam = o.AddComponent(); + cam.backgroundColor = Color.black; + cam.cullingMask = 0; + cam.clearFlags = CameraClearFlags.SolidColor; + cam.depth = -int.MaxValue; + cam.useOcclusionCulling = false; +#if UNITY_5_6_OR_NEWER + cam.allowHDR = false; + cam.allowMSAA = false; +#endif + cam.stereoTargetEye = StereoTargetEyeMask.None; + cam.renderingPath = RenderingPath.Forward; + o.hideFlags = HideFlags.HideInHierarchy; + return o; + + } + + /// + /// 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() + { + //If no change, then return + if (Screen.width == ScreenSizeX && Screen.height == ScreenSizeY) return; + + float windowaspect = (float)Screen.width / (float)Screen.height; + float scaleheight = windowaspect / TARGET_ASPECT; + + if (scaleheight < 1.0f) //Height is too large. Shrink it, adding letterboxes to the top and bottom. + { + Rect rect = cam.rect; + + rect.width = 1.0f; + rect.height = scaleheight; + rect.x = 0; + rect.y = (1.0f - scaleheight) / 2.0f; + + //cam.rect = rect; + } + else //Height is too small. Reduce width, adding pillarboxes to the sides. + { + float scalewidth = 1.0f / scaleheight; + + Rect rect = cam.rect; + + rect.width = scalewidth; + rect.height = 1.0f; + rect.x = (1.0f - scalewidth) / 2.0f; + rect.y = 0; + + cam.rect = rect; + } + + ScreenSizeX = Screen.width; + ScreenSizeY = Screen.height; + } + + + /// + /// Calls RescaleCamera(). Called in ZEDRenderingPlane's Update() function. + /// + public void Update() + { + RescaleCamera(); + } + + } + +} + + + + diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs.meta new file mode 100644 index 0000000..a984e6c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display/ZEDRenderingPlane.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0e14eefa25813a3489cc8b38d2027ac8 +timeCreated: 1514308730 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions.meta b/Assets/ZED/SDK/Helpers/Scripts/Interactions.meta new file mode 100644 index 0000000..1b42f8f --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9fb1089a4d58a834da08d629e6ff2667 +folderAsset: yes +timeCreated: 1507319337 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs new file mode 100644 index 0000000..53f6015 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs @@ -0,0 +1,97 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// ##DEPRECATED + + +using UnityEngine; + +/// +/// Interface for handling SteamVR and Oculus tracked controllers in the same way. +/// Implemented in ZEDSteamVRControllerManager and ZEDOculusControllerManager. +/// +public interface ZEDControllerManager +{ + /// + /// Whether controllers have been initialized. + /// + bool PadsAreInit { get;} + + /// + /// Checks if a button is down. + /// + /// Button to check. + /// ID of the controller to check. + /// + bool GetDown(sl.CONTROLS_BUTTON button, int controllerid = -1); + + /// + /// Checks if a trigger is down. + /// + /// Trigger to check. + /// ID of the controller to check. + /// + float GetHairTrigger(sl.CONTROLS_AXIS1D button, int controllerID = -1); + + /// + /// Gets the ID of the right controller. + /// + /// + int GetRightIndex(); + + /// + /// Gets the ID of the left controller. + /// + /// + int GetLeftIndex(); + + /// + /// Gets the local position of a controller. + /// + /// + /// + Vector3 GetPosition(int IDPad); + + /// + /// Loads the index of a controller according to files created from the ZED calibration tool. + /// + /// + void LoadIndex(string path); + + /// + /// 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/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs.meta new file mode 100644 index 0000000..4dd95bd --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e92efe4e88a87bb46b78648c71df9e87 +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs new file mode 100644 index 0000000..adec1aa --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs @@ -0,0 +1,740 @@ +using UnityEngine; +using UnityEngine.VR; +using System.Collections.Generic; +#if ZED_STEAM_VR +using Valve.VR; +#endif +#if UNITY_EDITOR +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 +{ + /// + /// Type of VR SDK loaded. 'Oculus', 'OpenVR' or empty. + /// + private string loadeddevice = ""; + +#if ZED_STEAM_VR //Only enabled if the SteamVR Unity plugin is detected. + + /// + /// OpenVR System class that lets us get inputs straight from the API, bypassing SteamVR. + /// This is necessary because different versions of SteamVR use completely different input systems. + /// + protected CVRSystem openvrsystem = OpenVR.System; + /// + /// State of the controller's buttons and axes. Used to check inputs. + /// + protected VRControllerState_t controllerstate; + /// + /// State of the controller's buttons and axes last frame. Used to check if buttons just went down or up. + /// + protected VRControllerState_t lastcontrollerstate; + /// + /// Size of VRControllerState_t class in bytes. Used to call GetControllerState from the OpenVR API. + /// + protected const uint controllerstatesize = 64; + /// + /// Enumerated version of the uint index SteamVR assigns to each device. + /// Converted from OpenVR.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole). + /// + public enum EIndex + { + None = -1, + Hmd = (int)OpenVR.k_unTrackedDeviceIndex_Hmd, + Device1, + Device2, + Device3, + Device4, + Device5, + Device6, + Device7, + Device8, + Device9, + Device10, + Device11, + Device12, + Device13, + Device14, + Device15 + } + [HideInInspector] + public EIndex index = EIndex.None; + + /// + /// 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 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 = 0.25f; + private Devices oldDevice; + + /// + /// If true, will use a direct API check to OpenVR's API to check if a button is down. + /// Does not work if using the SteamVR plugin 2.0 or higher as well as the action system it includes. + /// + [Tooltip("If true, will use a direct API check to OpenVR's API to check if a button is down.\r\n" + + "Does not work if using the SteamVR plugin 2.0 or higher as well as the action system it includes. ")] + public bool useLegacySteamVRInput = false; +#endif + + /// + /// 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>(); + + /// + /// Types of tracked devices. + /// + public enum Devices + { + RightController, + LeftController, + +#if ZED_STEAM_VR + ViveTracker, +#endif + Hmd, + }; + + + /// + /// 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; + + /// + /// If true, and this is a controller, will offset controller's position by the difference between + /// the VR headset and the ZED's tracked position. This keeps controller's position relative to the ZED. + /// + [Tooltip("If true, and this is a controller, will offset controller's position by the difference between " + + "the VR headset and the ZED's tracked position. This keeps controller's position relative to the ZED. ")] + [LabelOverride("Enable Controller Drift Fix")] + public bool correctControllerDrift = true; + + /// + /// 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 = ""; + + /// + /// Cached transform that represents the ZED's head, retrieved from ZEDManager.GetZedRootTransform(). + /// Used to find the offset between the HMD and tracked transform to compensate for drift. + /// + protected Transform zedRigRoot; + + /// + /// Reference to the scene's ZEDManager component. Used for compensating for headset drift when this is on a controller. + /// + [Tooltip("Reference to the scene's ZEDManager component. Used for compensating for headset drift when this is on a controller. " + + "If left blank, will be set to the first available ZEDManager.")] + public ZEDManager zedManager = null; + + /// + /// Sets up the timed pose dictionary and identifies the VR SDK being used. + /// + protected virtual void Awake() + { + 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.XR.XRSettings.loadedDeviceName; + + if (!zedManager) + { + zedManager = FindObjectOfType(); + //If there are multiple cameras in a scene, this arbitrary assignment could be bad. Warn the user. + if (ZEDManager.GetInstances().Count > 1) + { + //Using Log instead of LogWarning because most users don't enable warnings but this is actually important. + Debug.Log("Warning: ZEDController automatically set itself to first available ZED (" + zedManager.cameraID + ") because zedManager " + + "value wasn't set, but there are multiple ZEDManagers in the scene. Assign a reference directly to ensure no unexpected behavior."); + } + } + + if (zedManager) zedRigRoot = zedManager.GetZedRootTansform(); + } + + /// + /// Update is called every frame. + /// For SteamVR plugin this is where the device Index is set up. + /// For Oculus plugin this is where the tracking is done. + /// + protected virtual void Update() + { +#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 (OVRInput.GetConnectedControllers().ToString().ToLower().Contains("touch")) + { + //Depending on which tracked device we are looking for, start tracking it. + 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. + RegisterPosition(1, OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch), OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTouch)); + + if (deviceToTrack == Devices.Hmd) //Track the Oculus Hmd. + RegisterPosition(1, UnityEngine.XR.InputTracking.GetLocalPosition(UnityEngine.XR.XRNode.CenterEye), UnityEngine.XR.InputTracking.GetLocalRotation(UnityEngine.XR.XRNode.CenterEye)); + + //Use our saved positions to apply a delay before assigning it to this object's Transform. + if (poseData.Count > 0) + { + sl.Pose p; + + //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. + } + } + } + //Enable updating the internal state of OVRInput. + OVRInput.Update(); +#endif +#if ZED_STEAM_VR + + + UpdateControllerState(); //Get the button states so we can check if buttons are down or not. + + timerSteamVR += Time.deltaTime; //Increment timer for checking on devices + + if (timerSteamVR <= timerMaxSteamVR) + return; + + timerSteamVR = 0f; + + //Checks if a device has been assigned + if (index == EIndex.None && loadeddevice == "OpenVR") + { + //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 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++) + { + var result = new System.Text.StringBuilder((int)64); + OpenVR.System.GetStringTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_RenderModelName_String, result, 64, ref error); + if (result.ToString().Contains("tracker")) + { + index = (EIndex)i; + break; //We break out of the loop, but we can use this to set up multiple Vive Trackers if we want to. + } + } + } + + //Looks for a device with the role of a Right Hand. + 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) + { + index = (EIndex)OpenVR.System.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.LeftHand); + } + + //Assigns the HMD. + if (deviceToTrack == Devices.Hmd) + { + index = EIndex.Hmd; + } + + //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) // + { + //If the Serial number of the Calibrated device isn't the same as the current tracked device by this script... + var snerror = ETrackedPropertyError.TrackedProp_Success; + var snresult = new System.Text.StringBuilder((int)64); + OpenVR.System.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_SerialNumber_String, snresult, 64, ref snerror); + if (!snresult.ToString().Contains(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++) + { + //If a device with the same Serial Number is found, then change the device to track of this script. + var chsnresult = new System.Text.StringBuilder((int)64); + OpenVR.System.GetStringTrackedDeviceProperty((uint)i, ETrackedDeviceProperty.Prop_SerialNumber_String, chsnresult, 64, ref snerror); + if (snresult.ToString().Contains(SNHolder)) + { + index = (EIndex)i; + string deviceRole = OpenVR.System.GetControllerRoleForTrackedDeviceIndex((uint)index).ToString(); + if (deviceRole.Equals("RightHand")) + deviceToTrack = Devices.RightController; + else if (deviceRole.Equals("LeftHand")) + 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; + } + Debug.Log("A connected device with the correct Serial Number was found, and assigned to " + this + " the correct device to track."); + break; + } + } + } + } + oldDevice = deviceToTrack; + } + + if (deviceToTrack != oldDevice) + index = EIndex.None; + +#endif + } + +#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; } + + /// + /// Track the devices for SteamVR and applying a delay. + /// + protected void OnNewPoses(TrackedDevicePose_t newpose) + { + if (index == EIndex.None) + return; + + var i = (int)index; + + isValid = false; + + if (!newpose.bDeviceIsConnected) + return; + + if (!newpose.bPoseIsValid) + return; + + isValid = true; + + //Get the position and rotation of our tracked device. + var pose = new SteamVR_Utils.RigidTransform(newpose.mDeviceToAbsoluteTracking); + //Saving those values. + RegisterPosition(1, pose.pos, pose.rot); + + //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; + + } + + protected void OnEnable() + { + if (openvrsystem == null) + { + enabled = false; + return; + } + } + + protected void OnDisable() + { + isValid = false; + } + + protected virtual void UpdateControllerState() + { + lastcontrollerstate = controllerstate; + + //Update position. + if (index > EIndex.Hmd) + { + ETrackingUniverseOrigin tracktype = OpenVR.Compositor.GetTrackingSpace(); + TrackedDevicePose_t[] absoluteposes = new TrackedDevicePose_t[16]; + openvrsystem.GetDeviceToAbsoluteTrackingPose(tracktype, 0, absoluteposes); + TrackedDevicePose_t newposes = absoluteposes[(int)index]; + OnNewPoses(newposes); + } + + //We need to check for this always in case the user uses the deprecated GetVRButton methods. + if (useLegacySteamVRInput) + { + openvrsystem.GetControllerState((uint)index, ref controllerstate, controllerstatesize); + } + + } + + /// + /// Returns if the VR controller button with the given ID was pressed for the first time this frame. + /// + /// EVR ID of the button as listed in OpenVR. + [System.ObsoleteAttribute("ZEDControllerTracker's GetVRButton methods are deprecated.\r\n " + + "Use ZEDControllerTracker_DemoInputs.GetVRButtonDown_Legacy instead., false")] + public bool GetVRButtonDown(EVRButtonId buttonid) + { + if (openvrsystem == null) return false; //If VR isn't running, we can't check. + + bool washeldlastupdate = (lastcontrollerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + if (washeldlastupdate == true) return false; //If the key was held last check, it can't be pressed for the first time now. + + bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + return isheld; //If we got here, we know it was not down last frame. + + } + + /// + /// Returns if the VR controller button with the given ID is currently held. + /// + /// EVR ID of the button as listed in OpenVR. + [System.ObsoleteAttribute("ZEDControllerTracker's GetVRButton methods are deprecated.\r\n " + + "Use ZEDControllerTracker_DemoInputs.GetVRButtonHeld_Legacy instead.", false)] + public bool GetVRButtonHeld(EVRButtonId buttonid) + { + if (openvrsystem == null) return false; //If VR isn't running, we can't check. + + bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + return isheld; + } + + /// + /// Returns if the VR controller button with the given ID was held last frame, but released this frame. + /// + /// EVR ID of the button as listed in OpenVR. + [System.ObsoleteAttribute("ZEDControllerTracker's GetVRButton methods are deprecated.\r\n " + + "Use ZEDControllerTracker_DemoInputs.GetVRButtonReleased_Legacy instead.", false)] + public bool GetVRButtonReleased(EVRButtonId buttonid) + { + if (openvrsystem == null) return false; //If VR isn't running, we can't check. + + bool washeldlastupdate = (lastcontrollerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + if (washeldlastupdate == false) return false; //If the key was held last check, it can't be released now. + + bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + return !isheld; //If we got here, we know it was not up last frame. + } + + /// + /// Returns the value of an axis with the provided ID. + /// Note that for single-value axes, the relevant value will be the X in the returned Vector2 (the Y is unused). + /// + /// + [System.ObsoleteAttribute("ZEDControllerTracker.GetAxis is deprecated.\r\n " + + "Use ZEDControllerTracker_DemoInputs.GetVRAxis_Legacy instead.", false)] + public Vector2 GetAxis(EVRButtonId buttonid) + { + //Convert the EVRButtonID enum to the axis number and check if it's not an axis. + uint axis = (uint)buttonid - (uint)EVRButtonId.k_EButton_Axis0; + if (axis < 0 || axis > 4) + { + Debug.LogError("Called GetAxis with " + buttonid + ", which is not an axis."); + return Vector2.zero; + } + + switch (axis) + { + case 0: return new Vector2(controllerstate.rAxis0.x, controllerstate.rAxis0.y); + case 1: return new Vector2(controllerstate.rAxis1.x, controllerstate.rAxis1.y); + case 2: return new Vector2(controllerstate.rAxis2.x, controllerstate.rAxis2.y); + case 3: return new Vector2(controllerstate.rAxis3.x, controllerstate.rAxis3.y); + case 4: return new Vector2(controllerstate.rAxis4.x, controllerstate.rAxis4.y); + default: return Vector2.zero; + } + } + +#endif + /// + /// Compute the delayed position and rotation from the history stored in the poseData dictionary. + /// + /// + /// + /// + private sl.Pose GetValuePosition(int keyindex, float timeDelay) + { + sl.Pose p = new sl.Pose(); + if (poseData.ContainsKey(keyindex)) + { + //Get the saved position & 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[keyindex].Count; ++i) + { + 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[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; + + //Add drift correction, but only if the user hasn't disabled it, it's on an actual controller, and the zedRigRoot position won't be affected. + if (correctControllerDrift == true && + (deviceToTrack == Devices.LeftController || deviceToTrack == Devices.RightController) && + (zedManager != null && zedManager.IsStereoRig == true && !zedManager.transform.IsChildOf(transform))) + { + //Compensate for positional drift by measuring the distance between HMD and ZED rig root (the head's center). + Vector3 zedhmdposoffset = zedRigRoot.position - UnityEngine.XR.InputTracking.GetLocalPosition(UnityEngine.XR.XRNode.Head); + p.translation += zedhmdposoffset; + } + + //Removes used elements from the dictionary. + poseData[keyindex].RemoveRange(0, currentIndex - 1); + } + return p; + } + } + } + return p; + } + + /// + /// Set the current tracking to a container (TimedPoseData) to be stored in poseData and retrieved/applied after the latency period. + /// + /// 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[keyindex].Add(currentPoseData); + + } + + /// + /// 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 +{ + [SerializeField] + static string defineName; + static string packageName; + + public override void OnInspectorGUI() //Called when the Inspector is visible. + { + //if (CheckPackageExists("OpenVR")) + if (CheckPackageExists("SteamVR_Camera.cs")) + { + defineName = "ZED_STEAM_VR"; + packageName = "SteamVR"; + } + //else if (CheckPackageExists("Oculus") || CheckPackageExists("OVR")) + else if (CheckPackageExists("OVRManager")) + { + defineName = "ZED_OCULUS"; + packageName = "Oculus"; + } + + if (EditorPrefs.GetBool(packageName)) //Has it been set? + { + DrawDefaultInspector(); + } + else //No package loaded, but one has been detected. Present a button to load it. + { + GUILayout.Space(20); + if (GUILayout.Button("Load " + packageName + " data")) + { + if (CheckPackageExists(packageName)) + { + ActivateDefine(); + } + } + if (packageName == "SteamVR") + EditorGUILayout.HelpBox(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.STEAMVR_NOT_INSTALLED), MessageType.Warning); + else if (packageName == "Oculus") + EditorGUILayout.HelpBox(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.OVR_NOT_INSTALLED), MessageType.Warning); + } + } + + /// + /// 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; + } + + + /// + /// 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); + string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone); + if (defines.Length != 0) + { + if (!defines.Contains(defineName)) + { + defines += ";" + defineName; + } + } + else + { + if (!defines.Contains(defineName)) + { + defines += defineName; + } + } + PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, defines); + } + + /// + /// 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(string packagename) + { + EditorPrefs.SetBool(packagename, false); + string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone); + if (defines.Length != 0) + { + if (defineName != null && defines.Contains(defineName)) + { + defines = defines.Remove(defines.IndexOf(defineName), defineName.Length); + + if (defines.LastIndexOf(";") == defines.Length - 1 && defines.Length != 0) + { + defines.Remove(defines.LastIndexOf(";"), 1); + } + } + } + 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) + { + if (CheckPackageExists("OVRManager")) + { + defineName = "ZED_OCULUS"; + packageName = "Oculus"; + ActivateDefine(); + } + else + { + defineName = "ZED_OCULUS"; + DeactivateDefine("Oculus"); + } + + //if (CheckPackageExists("OpenVR")) + if (CheckPackageExists("SteamVR_Camera")) //"OpenVR" and "SteamVR" exist in script names in the Oculus plugin. + { + defineName = "ZED_STEAM_VR"; + packageName = "SteamVR"; + ActivateDefine(); + } + else + { + defineName = "ZED_STEAM_VR"; + DeactivateDefine("SteamVR"); + } + + if (CheckPackageExists("SteamVR_Input_Sources")) + { + defineName = "ZED_SVR_2_0_INPUT"; + //packageName = "SteamVR"; + ActivateDefine(); + } + else + { + defineName = "ZED_SVR_2_0_INPUT"; + DeactivateDefine("SteamVR"); + } + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs.meta new file mode 100644 index 0000000..1edf38d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 454b1f0b0de2bb644a283d964ccf7f06 +timeCreated: 1527770888 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker_DemoInputs.cs b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker_DemoInputs.cs new file mode 100644 index 0000000..b952d3c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker_DemoInputs.cs @@ -0,0 +1,506 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +#if ZED_STEAM_VR +using Valve.VR; +#endif + +/// +/// Extended version of ZEDControllerTracker that also checks for several inputs in a generic way. +/// You can check a state with +/// Used because input methods vary a lot between controllers and between SteamVR (new and old) and Oculus. +/// See base class ZEDControllerTracker for any code that don't directly relate to inputs. +/// +public class ZEDControllerTracker_DemoInputs : ZEDControllerTracker +{ + //#if ZED_STEAM_VR +#if ZED_SVR_2_0_INPUT + + /// + /// SteamVR action to cause a Fire event when checked or subscribed to. + /// + [Header("SteamVR Plugin 2.0 Bindings")] + [Tooltip("SteamVR action to cause a Fire event when checked or subscribed to.")] + public SteamVR_Action_Boolean fireBinding = SteamVR_Input.GetAction("Fire"); + /// + /// SteamVR action to cause a Click event when checked or subscribed to. + /// + [Tooltip("SteamVR action to cause a Click event when checked or subscribed to.")] + public SteamVR_Action_Boolean clickBinding = SteamVR_Input.GetAction("Click"); + /// + /// SteamVR action to cause a Back event when checked or subscribed to. + /// + [Tooltip("SteamVR action to cause a Back event when checked or subscribed to.")] + public SteamVR_Action_Boolean backBinding = SteamVR_Input.GetAction("Back"); + /// + /// SteamVR action to cause a Grab event when checked or subscribed to. + /// + [Tooltip("SteamVR action to cause a Grab event when checked or subscribed to.")] + public SteamVR_Action_Boolean grabBinding = SteamVR_Input.GetAction("Grab"); + /// + /// SteamVR action to cause a Vector2 UI navigation event when checked or subscribed to. + /// + [Tooltip("SteamVR action to cause a UI navigation event when checked or subscribed to.")] + public SteamVR_Action_Vector2 navigateUIBinding = SteamVR_Input.GetAction("NavigateUI"); + + +#elif ZED_STEAM_VR + /// + /// Legacy SteamVR button to cause a Fire event when checked or subscribed to. + /// + [Header("SteamVR Legacy Input Bindings")] + [Tooltip("Legacy SteamVR button to cause a Fire event when checked or subscribed to.")] + public EVRButtonId fireBinding_Legacy = EVRButtonId.k_EButton_SteamVR_Trigger; + /// + /// Legacy SteamVR button to cause a Click event when checked or subscribed to. + /// + [Tooltip("Legacy SteamVR button to cause a Click event when checked or subscribed to.")] + public EVRButtonId clickBinding_Legacy = EVRButtonId.k_EButton_SteamVR_Trigger; + /// + /// Legacy SteamVR button to cause a Back event when checked or subscribed to. + /// + [Tooltip("Legacy SteamVR button to cause a Back event when checked or subscribed to.")] + public EVRButtonId backBinding_Legacy = EVRButtonId.k_EButton_Grip; + /// + /// Legacy SteamVR button to cause a Grip event when checked or subscribed to. + /// + [Tooltip("Legacy SteamVR button to cause a Grip event when checked or subscribed to.")] + public EVRButtonId grabBinding_Legacy = EVRButtonId.k_EButton_SteamVR_Trigger; + /// + /// Legacy SteamVR axis to cause a Vector2 Navigate UI event when checked or subscribed to. + /// + [Tooltip("Legacy SteamVR button to cause a Vector2 Navigate UI event when checked or subscribed to.")] + public EVRButtonId navigateUIBinding_Legacy = EVRButtonId.k_EButton_Axis0; +#endif + +#if ZED_OCULUS + /// + /// Oculus Button checked to signal a Fire event when checked or subscribed to. + /// + [Header("Oculus Input Bindings")] + [Tooltip("Oculus Button checked to signal a Fire event when checked or subscribed to")] + public OVRInput.Button fireButton = OVRInput.Button.PrimaryIndexTrigger; + /// + /// Oculus Button checked to signal a Click event when checked or subscribed to. + /// + [Tooltip("Oculus Button checked to signal a Click event when checked or subscribed to")] + public OVRInput.Button clickButton = OVRInput.Button.PrimaryIndexTrigger; + /// + /// Oculus Button checked to signal a Back event when checked or subscribed to. + /// + [Tooltip("Oculus Button checked to signal a Back event when checked or subscribed to")] + public OVRInput.Button backButton = OVRInput.Button.Two; //Y, or B if just right controller is connected. + /// + /// Oculus Button checked to signal a Grab event when checked or subscribed to. + /// + [Tooltip("Oculus Button checked to signal a Grab event when checked or subscribed to")] + public OVRInput.Button grabButton = OVRInput.Button.PrimaryHandTrigger; + /// + /// Oculus Button checked to signal a Vector2 UI navigation event when checked or subscribed to. + /// + [Tooltip("Oculus Button checked to signal a Vector2 UI navigation event when checked or subscribed to")] + public OVRInput.Axis2D navigateUIAxis = OVRInput.Axis2D.PrimaryThumbstick; + + public static bool ovrUpdateCalledThisFrame = false; +#endif + + /// + /// Events called when the Fire button/action was just pressed. + /// + [Header("Events")] + [Space(5)] + [Tooltip("Events called when the Fire button/action was just pressed.")] + public UnityEvent onFireDown; + /// + /// Events called when the Fire button/action was just released. + /// + [Tooltip("Events called when the Fire button/action was just released.")] + public UnityEvent onFireUp; + /// + /// Events called when the Click button/action was just pressed. + /// + [Tooltip("Events called when the Click button/action was just pressed.")] + public UnityEvent onClickDown; + /// + /// Events called when the Click button/action was just released. + /// + [Tooltip("Events called when the Click button/action was just released.")] + public UnityEvent onClickUp; + /// + /// Events called when the Back button/action was just pressed. + /// + [Tooltip("Events called when the Back button/action was just pressed.")] + public UnityEvent onBackDown; + /// + /// Events called when the Back button/action was just released. + /// + [Tooltip("Events called when the Back button/action was just released.")] + public UnityEvent onBackUp; + /// + /// Events called when the Grab button/action was just pressed. + /// + [Tooltip("Events called when the Grab button/action was just pressed.")] + public UnityEvent onGrabDown; + /// + /// Events called when the Grab button/action was just released. + /// + [Tooltip("Events called when the Grab button/action was just released.")] + public UnityEvent onGrabUp; + + /// + /// Returns if the Fire button/action matched the provided state. + /// + /// Whether to check if the button/action is just pressed, just released, or is being held down. + public bool CheckFireButton(ControllerButtonState state) + { +#if ZED_SVR_2_0_INPUT + return CheckSteamVRBoolActionState(fireBinding, state); +#elif ZED_STEAM_VR + return CheckSteamVRButtonState_Legacy(fireBinding_Legacy, state); +#endif + +#if ZED_OCULUS + return CheckOculusButtonState(fireButton, state); +#endif + return false; + } + + /// + /// Returns if the Click button/action matched the provided state. + /// + /// Whether to check if the button/action is just pressed, just released, or is being held down. + public bool CheckClickButton(ControllerButtonState state) + { +#if ZED_SVR_2_0_INPUT + return CheckSteamVRBoolActionState(clickBinding, state); +#elif ZED_STEAM_VR + return CheckSteamVRButtonState_Legacy(clickBinding_Legacy, state); +#endif + +#if ZED_OCULUS + return CheckOculusButtonState(clickButton, state); +#endif + return false; + } + + /// + /// Returns if the Back button/action matched the provided state. + /// + /// Whether to check if the button/action is just pressed, just released, or is being held down. + public bool CheckBackButton(ControllerButtonState state) + { +#if ZED_SVR_2_0_INPUT + return CheckSteamVRBoolActionState(backBinding, state); +#elif ZED_STEAM_VR + return CheckSteamVRButtonState_Legacy(backBinding_Legacy, state); +#endif +#if ZED_OCULUS + return CheckOculusButtonState(backButton, state); +#endif + return false; + } + + /// + /// Returns if the Grab button/action matched the provided state. + /// + /// Whether to check if the button/action is just pressed, just released, or is being held down. + public bool CheckGrabButton(ControllerButtonState state) + { +#if ZED_SVR_2_0_INPUT + return CheckSteamVRBoolActionState(grabBinding, state); +#elif ZED_STEAM_VR + return CheckSteamVRButtonState_Legacy(grabBinding_Legacy, state); +#endif +#if ZED_OCULUS + return CheckOculusButtonState(grabButton, state); +#endif + return false; + } + + /// + /// Returns the current 2D axis value of the NavigateUIAxis button/action. + /// + public Vector2 CheckNavigateUIAxis() + { +#if ZED_SVR_2_0_INPUT + return CheckSteamVR2DAxis(navigateUIBinding); +#elif ZED_STEAM_VR + return CheckSteamVRAxis_Legacy(navigateUIBinding_Legacy); +#endif + +#if ZED_OCULUS + return CheckOculus2DAxisState(navigateUIAxis); +#endif + return Vector3.zero; + } + + protected override void Awake() + { + base.Awake(); + +#if ZED_SVR_2_0_INPUT + if (!useLegacySteamVRInput) + { + if(!SteamVR.active) SteamVR.Initialize(true); //Force SteamVR to activate, so we can use the input system. + } +#endif + } + + protected override void Update() + { + base.Update(); + + if (CheckClickButton(ControllerButtonState.Down)) onClickDown.Invoke(); + if (CheckClickButton(ControllerButtonState.Up)) onClickUp.Invoke(); + if (CheckFireButton(ControllerButtonState.Down)) onFireDown.Invoke(); + if (CheckFireButton(ControllerButtonState.Up)) onFireUp.Invoke(); + if (CheckBackButton(ControllerButtonState.Down)) onBackDown.Invoke(); + if (CheckBackButton(ControllerButtonState.Up)) onBackUp.Invoke(); + if (CheckGrabButton(ControllerButtonState.Down)) onGrabDown.Invoke(); + if (CheckGrabButton(ControllerButtonState.Up)) onGrabUp.Invoke(); + } + + protected void LateUpdate() + { +#if ZED_OCULUS + ovrUpdateCalledThisFrame = false; +#endif + } + +#if ZED_STEAM_VR + protected override void UpdateControllerState() + { + base.UpdateControllerState(); + + //If using legacy SteamVR input, we check buttons directly from the OpenVR API. +#if ZED_SVR_2_0_INPUT //If using SteamVR plugin 2.0 or higher, give the option to use legacy input. + if (useLegacySteamVRInput) + { + openvrsystem.GetControllerState((uint)index, ref controllerstate, controllerstatesize); + } +#else //We're using an older SteamVR plugin, so we need to use the legacy input. + openvrsystem.GetControllerState((uint)index, ref controllerstate, controllerstatesize); +#endif + } +#endif + +#if ZED_OCULUS + /// + /// Checks the button state of a given Oculus button. + /// + /// Whether to check if the button/action is just pressed, just released, or is being held down. + public bool CheckOculusButtonState(OVRInput.Button button, ControllerButtonState state) + { + if (!ovrUpdateCalledThisFrame) + { + OVRInput.Update(); + ovrUpdateCalledThisFrame = true; + } + + bool result = false; + switch (state) + { + case ControllerButtonState.Down: + result = OVRInput.GetDown(button, GetOculusController()); + break; + case ControllerButtonState.Held: + result = OVRInput.Get(button, GetOculusController()); + break; + case ControllerButtonState.Up: + result = OVRInput.GetUp(button, GetOculusController()); + break; + } + return result; + } + + /// + /// Returns the axis of a given Oculus axis button/joystick. + /// + public Vector3 CheckOculus2DAxisState(OVRInput.Axis2D axis) + { + if (!ovrUpdateCalledThisFrame) + { + OVRInput.Update(); + ovrUpdateCalledThisFrame = true; + } + + return OVRInput.Get(axis, GetOculusController()); + } + + /// + /// Returns the Oculus controller script of the controller currently attached to this object. + /// + public OVRInput.Controller GetOculusController() + { + if (deviceToTrack == Devices.LeftController) return OVRInput.Controller.LTouch; + else if (deviceToTrack == Devices.RightController) return OVRInput.Controller.RTouch; + else return OVRInput.Controller.None; + } + + /// + /// Returns if this script is bound to an Oculus Touch controller that is currently not connected. + /// For example, if it's a Right Controller but only the left is connected, it returns false. + /// If not bound to a controller, returns true. + /// + /// + private bool IsConnectedController() + { + if (!objecttracker) return true; //Not attached to a tracker. Return true since it doesn't depend on a controller to be alive. + if (objecttracker.deviceToTrack != ZEDControllerTracker.Devices.LeftController && objecttracker.deviceToTrack != ZEDControllerTracker.Devices.RightController) + return true; //Not bound to a left or right controller, so let it live. + + + string connectedcontrollers = OVRInput.GetConnectedControllers().ToString().ToLower(); + if (connectedcontrollers == "touch") return true; //Both controllers are connected, so + if (objecttracker.deviceToTrack == ZEDControllerTracker.Devices.LeftController && connectedcontrollers == "ltouch") return true; //Left controller only. + if (objecttracker.deviceToTrack == ZEDControllerTracker.Devices.RightController && connectedcontrollers == "rtouch") return true; //Right controller only. + + return false; + } + +#endif + + + //#if ZED_STEAM_VR +#if ZED_SVR_2_0_INPUT + /// + /// Checks the button state of a given SteamVR boolean action. + /// + /// Whether to check if the button/action is just pressed, just released, or is being held down. + protected bool CheckSteamVRBoolActionState(SteamVR_Action_Boolean action, ControllerButtonState buttonstate) + { + switch(buttonstate) + { + case ControllerButtonState.Down: + return action.GetLastStateDown(GetSteamVRInputSource()); + case ControllerButtonState.Held: + return action.GetLastState(GetSteamVRInputSource()); + case ControllerButtonState.Up: + return action.GetLastStateUp(GetSteamVRInputSource()); + default: + return false; + } + } + + /// + /// Returns the axis of a given SteamVR 2D action. + /// + protected Vector2 CheckSteamVR2DAxis(SteamVR_Action_Vector2 action) + { + return action.GetAxis(GetSteamVRInputSource()); + } + + public SteamVR_Input_Sources GetSteamVRInputSource() + { + if (deviceToTrack == Devices.LeftController) return SteamVR_Input_Sources.LeftHand; + else if (deviceToTrack == Devices.RightController) return SteamVR_Input_Sources.RightHand; + else return SteamVR_Input_Sources.Camera; + } +#elif ZED_STEAM_VR + public bool CheckSteamVRButtonState_Legacy(EVRButtonId button, ControllerButtonState state) + { + switch(state) + { + case ControllerButtonState.Down: + return GetVRButtonDown_Legacy(button); + case ControllerButtonState.Held: + default: + return GetVRButtonHeld_Legacy(button); + case ControllerButtonState.Up: + return GetVRButtonReleased_Legacy(button); + } + } + + /// + /// Returns if the VR controller button with the given ID was pressed for the first time this frame. + /// + /// EVR ID of the button as listed in OpenVR. + public bool GetVRButtonDown_Legacy(EVRButtonId buttonid) + { + if (openvrsystem == null) return false; //If VR isn't running, we can't check. + + bool washeldlastupdate = (lastcontrollerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + if (washeldlastupdate == true) return false; //If the key was held last check, it can't be pressed for the first time now. + + bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + return isheld; //If we got here, we know it was not down last frame. + + } + + /// + /// Returns if the VR controller button with the given ID is currently held. + /// + /// EVR ID of the button as listed in OpenVR. + public bool GetVRButtonHeld_Legacy(EVRButtonId buttonid) + { + if (openvrsystem == null) return false; //If VR isn't running, we can't check. + + bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + return isheld; + } + + /// + /// Returns if the VR controller button with the given ID was held last frame, but released this frame. + /// + /// EVR ID of the button as listed in OpenVR. + public bool GetVRButtonReleased_Legacy(EVRButtonId buttonid) + { + if (openvrsystem == null) return false; //If VR isn't running, we can't check. + + bool washeldlastupdate = (lastcontrollerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + if (washeldlastupdate == false) return false; //If the key was held last check, it can't be released now. + + bool isheld = (controllerstate.ulButtonPressed & (1UL << (int)buttonid)) > 0L; + return !isheld; //If we got here, we know it was not up last frame. + } + + /// + /// Returns the value of an axis with the provided ID. + /// Note that for single-value axes, the relevant value will be the X in the returned Vector2 (the Y is unused). + /// + /// + public Vector2 CheckSteamVRAxis_Legacy(EVRButtonId buttonid) + { + //Convert the EVRButtonID enum to the axis number and check if it's not an axis. + uint axis = (uint)buttonid - (uint)EVRButtonId.k_EButton_Axis0; + if (axis < 0 || axis > 4) + { + Debug.LogError("Called GetAxis with " + buttonid + ", which is not an axis."); + return Vector2.zero; + } + + switch (axis) + { + case 0: return new Vector2(controllerstate.rAxis0.x, controllerstate.rAxis0.y); + case 1: return new Vector2(controllerstate.rAxis1.x, controllerstate.rAxis1.y); + case 2: return new Vector2(controllerstate.rAxis2.x, controllerstate.rAxis2.y); + case 3: return new Vector2(controllerstate.rAxis3.x, controllerstate.rAxis3.y); + case 4: return new Vector2(controllerstate.rAxis4.x, controllerstate.rAxis4.y); + default: return Vector2.zero; + } + } + +#endif +} + +/// +/// List of possible button states, used to check inputs. +/// +public enum ControllerButtonState +{ + /// + /// The button was pressed this frame. + /// + Down, + /// + /// The button is being held down - it doesn't matter which frame it started being held. + /// + Held, + /// + /// The button was released this frame. + /// + Up +} \ No newline at end of file diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker_DemoInputs.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker_DemoInputs.cs.meta new file mode 100644 index 0000000..4150bcd --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDControllerTracker_DemoInputs.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 133b3bfe60baacd45a72714ffc6eb29a +timeCreated: 1556646801 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs new file mode 100644 index 0000000..d65fae3 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs @@ -0,0 +1,303 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; +using System.IO; +#if UNITY_EDITOR +using UnityEditor; +#endif + +/// +/// 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 offset file name. + /// + [SerializeField] + public static string ZEDOffsetFile = "ZED_Position_Offset.conf"; + + /// + /// Where to save the ZED offset file. + /// + private string path = @"Stereolabs\steamvr"; + + /// + /// 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 local position/rotation of the ZED into an offset file. + /// + public void SaveZEDPos() + { + using (System.IO.StreamWriter file = new System.IO.StreamWriter(path)) + { + string tx = "x=" + transform.localPosition.x.ToString() + " //Translation x"; + string ty = "y=" + transform.localPosition.y.ToString() + " //Translation y"; + string tz = "z=" + transform.localPosition.z.ToString() + " //Translation z"; + string rx = "rx=" + transform.localRotation.eulerAngles.x.ToString() + " //Rotation x"; + 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); + file.WriteLine(rx); + file.WriteLine(ry); + file.WriteLine(rz); + + +#if ZED_STEAM_VR + if (TrackerComponentExist()) + { + //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 result = "indexController = "; + if (controllerTracker.index > 0) + { + var snerror = Valve.VR.ETrackedPropertyError.TrackedProp_Success; + var snresult = new System.Text.StringBuilder((int)64); + result += Valve.VR.OpenVR.System.GetStringTrackedDeviceProperty((uint)controllerTracker.index, Valve.VR.ETrackedDeviceProperty.Prop_SerialNumber_String, snresult, 64, ref snerror); + //OpenVR.System.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_SerialNumber_String, snresult, 64, ref snerror); + + } + else + { + result += "NONE"; + } + file.WriteLine(result); + } +#endif + + file.Close(); //Finalize the new file. + } + } + + /// + /// 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 (controllerTracker != null) + return true; + else + return false; + } + + private void OnEnable() + { + LoadTrackerComponent(); + } + + /// + /// 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 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() + { + LoadTrackerComponent(); + + string folder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData); + string specificFolder = Path.Combine(folder, @"Stereolabs\steamvr"); + path = Path.Combine(specificFolder, ZEDOffsetFile); + + // Check if folder exists and if not, create it + if (!Directory.Exists(specificFolder)) + Directory.CreateDirectory(specificFolder); + + + LoadZEDPos(); + CreateFileWatcher(specificFolder); + + isReady = true; + } + + private void Update() + { + if (isReady) + LoadZEDPos(); + } + + /// + /// Loads the offset file and sets the local position/rotation to the loaded values. + /// + public void LoadZEDPos() + { + if (!System.IO.File.Exists(path)) return; + + string[] lines = null; + try + { + lines = System.IO.File.ReadAllLines(path); + } + catch (System.Exception) + { + controllerTracker.SNHolder = "NONE"; + } + if (lines == null) + { + controllerTracker.SNHolder = "NONE"; + return; + } + if (lines == null) return; + Vector3 position = new Vector3(0, 0, 0); + Vector3 eulerRotation = new Vector3(0, 0, 0); + foreach (string line in lines) + { + string[] splittedLine = line.Split('='); + if (splittedLine != null && splittedLine.Length >= 2) + { + string key = splittedLine[0]; + string field = splittedLine[1].Split(' ')[0]; + + if (key == "x") + { + position.x = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "y") + { + position.y = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "z") + { + position.z = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "rx") + { + eulerRotation.x = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "ry") + { + eulerRotation.y = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "rz") + { + eulerRotation.z = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "indexController") + { + LoadTrackerComponent(); + + if (TrackerComponentExist()) + { + controllerTracker.SNHolder = field; + } + } + } + } + transform.localPosition = position; + 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. + 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; + // Only watch text files. + watcher.Filter = ZEDOffsetFile; + + // Add event handlers. + watcher.Changed += new FileSystemEventHandler(OnChanged); + + // Begin watching. + watcher.EnableRaisingEvents = true; + } + + /// + /// 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 (TrackerComponentExist()) + { + LoadZEDPos(); + } + } +} + +#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 +{ + private ZEDOffsetController positionManager; + + public void OnEnable() + { + positionManager = (ZEDOffsetController)target; + + } + + public override void OnInspectorGUI() //Called when the Inspector GUI becomes visible, or changes at all. + { + GUILayout.Space(5); + EditorGUILayout.BeginHorizontal(); + + EditorGUILayout.EndHorizontal(); + EditorGUILayout.BeginHorizontal(); + + GUI.enabled = positionManager.isReady; + 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(); + } + 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(); + } + EditorGUILayout.EndHorizontal(); + } +} + +#endif diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs.meta new file mode 100644 index 0000000..aa6c741 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDOffsetController.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f6e37f9a7dba18f489fce17f647b73a2 +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs new file mode 100644 index 0000000..603b333 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs @@ -0,0 +1,352 @@ +using System.Collections; +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 variables + + /// + /// Rotational reference point for moving forward, backward, left, right, etc. + /// + [Header("Object motion relative to:")] + [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; + + /// + /// 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; + + /// + /// Reference to the scene's ZEDManager component. + /// Used when RelativeMotion is set to Camera, for finding the current position of the ZED. + /// + [Tooltip("Reference to the scene's ZEDManager component. Used when RelativeMotion is set to Camera, " + + "and also for positioning it at start. If left blank, the first ZED camera indexed will be set.")] + public ZEDManager zedManager = null; + + + /// + /// 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(); + + /// + /// 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; + + + /// + /// Whether the object is moving/translating. + /// + private bool isMoving; + + private IEnumerator Start() + { + isMoving = false; + + if (!zedManager) + { + zedManager = FindObjectOfType(); + if (ZEDManager.GetInstances().Count > 1) //They let the plugin auto-assign a ZED but there are multiple ZED's. Warn the user. + { + Debug.Log("Warning: ZEDTransformController's zedManager field was not specified, but there are multiple ZEDManagers in the scene " + + "so first available ZED was assigned. This can cause the object to move relative to the wrong camera. " + + "It's recommended to assign the desired ZEDManager in the Inspector."); + } + } + + + //Find the available VR controllers and assigning them to our List. + yield return new WaitForSeconds(1f); + + var trackers = FindObjectsOfType(); + foreach (ZEDControllerTracker_DemoInputs tracker in trackers) + { + objectTrackers.Add(tracker); + } + + if (repositionAtStart) //If the user wants, move the object in front of the ZED once it's initialized. + { + zedManager.OnZEDReady += RepositionInFrontOfZED; + } + } + + private void Update() + { + 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 * 360) * Time.deltaTime; + } + if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.E)) + { + inputRotation = 1 * (rotationSpeed * 360) * Time.deltaTime; + } + if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W)) + { + moveAxis = Vector3.forward * movementSpeed * Time.deltaTime; + } + if (Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S)) + { + moveAxis = Vector3.back * movementSpeed * Time.deltaTime; + } + if (Input.GetKey(KeyCode.A)) + { + moveAxis = Vector3.left * movementSpeed * Time.deltaTime; + } + if (Input.GetKey(KeyCode.D)) + { + moveAxis = Vector3.right * movementSpeed * Time.deltaTime; + } + if (Input.GetKey(KeyCode.R)) + { + moveAxis = Vector3.up * movementSpeed * Time.deltaTime; + } + if (Input.GetKey(KeyCode.F)) + { + moveAxis = Vector3.down * movementSpeed * Time.deltaTime; + } + + Quaternion gravity = Quaternion.identity; + + + if (moveAxis != Vector3.zero) + { + isMoving = true; + if (motion == RelativeMotion.Itself) + { + transform.Translate(moveAxis.x, moveAxis.y, moveAxis.z); + } + else if (motion == RelativeMotion.Camera) + { + gravity = Quaternion.FromToRotation(zedManager.GetZedRootTansform().up, Vector3.up); + transform.localPosition += zedManager.GetMainCameraTransform().right * moveAxis.x; + transform.localPosition += zedManager.GetMainCameraTransform().forward * moveAxis.z; + transform.localPosition += gravity * zedManager.GetMainCameraTransform().up * moveAxis.y; + } + } + else + { + isMoving = false; + } + + if (Input.GetKey(KeyCode.Mouse0)) + inputScale = 1f; + else if (Input.GetKey(KeyCode.Mouse1)) + inputScale = -1f; + + if (zedManager) + { + Vector3 moveaxis = new Vector3(); //Position change by controller. Added to keyboard version if both are applied. + + //Looks for any input from this controller through SteamVR. + //Left controller controls rotation and increasing scale. + if (objectTrackers.Count > 0) + { + moveaxis = objectTrackers[0].CheckNavigateUIAxis(); + if (Mathf.Abs(moveaxis.x) < 0.1f) moveaxis.x = 0; //Add slight deadzone. + if (Mathf.Abs(moveaxis.y) < 0.1f) moveaxis.y = 0; + inputRotation += moveaxis.x * rotationSpeed * 360f * Time.deltaTime; + + gravity = Quaternion.FromToRotation(zedManager.GetZedRootTansform().up, Vector3.up); + transform.localPosition += gravity * zedManager.GetMainCameraTransform().up * moveaxis.y * movementSpeed * Time.deltaTime; + + if (objectTrackers[0].CheckClickButton(ControllerButtonState.Held)) + { + inputScale = 1f; + } + } + //Right controller controls translation and lowering scale. + if (objectTrackers.Count > 1) + { + moveaxis = objectTrackers[1].CheckNavigateUIAxis(); + if (Mathf.Abs(moveaxis.x) < 0.1f) moveaxis.x = 0; //Add slight deadzone. + if (Mathf.Abs(moveaxis.y) < 0.1f) moveaxis.y = 0; + if (moveaxis.x != 0 || moveaxis.y != 0) + { + isMoving = true; + gravity = Quaternion.FromToRotation(zedManager.GetZedRootTansform().up, Vector3.up); + transform.localPosition += zedManager.GetMainCameraTransform().right * moveaxis.x * movementSpeed * Time.deltaTime; + transform.localPosition += gravity * zedManager.GetMainCameraTransform().forward * moveaxis.y * movementSpeed * Time.deltaTime; + } + else + isMoving = false; + + if (objectTrackers[1].CheckClickButton(ControllerButtonState.Held)) + { + inputScale = -1f; + } + } + } + + //Rotation + float h = inputRotation; + + if (invertRotation) + transform.Rotate(0, h, 0); + else + transform.Rotate(0, -h, 0); + + //Scale + float s = scaleSpeed * (inputScale * Time.deltaTime); + + transform.localScale = new Vector3(transform.localScale.x + s, + transform.localScale.y + s, + transform.localScale.z + s); + + if (transform.localScale.x > maxScale) + transform.localScale = new Vector3(maxScale, maxScale, maxScale); + else if (transform.localScale.x < minScale) + transform.localScale = new Vector3(minScale, minScale, minScale); + + //Enable/disable light if moving. + if (spotLight != null) + { + SetMovementLight(); + } + } + + /// + /// 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 the object is moving. + if (!spotLight.enabled && isMoving) + { + spotLight.enabled = true; + } + else if (spotLight.enabled && !isMoving) + { + spotLight.enabled = false; + } + + //Scale light with object size. + if (spotLight.enabled && spotLight.type == LightType.Spot) + { + spotLight.spotAngle = transform.localScale.x * 180 * 2; + spotLight.range = transform.localScale.x * 4f; + if (spotLight.range > 2) + spotLight.range = 2; + } + } + + /// + /// Repositions the object to a meter in front of the ZED. + /// Called by ZEDManager.OnZEDReady if repositionAtStart is enabled. + /// + void RepositionInFrontOfZED() + { + //If the ZEDManager uses Estimate Initial Position and tracking, then the position will change shortly after OnZEDReady. + //We'll make a non-async call to EstimateInitialPosition to determine what the angle will be. + if (zedManager.estimateInitialPosition && zedManager.enableTracking) + { + Vector3 initpos = Vector3.zero; + Quaternion initrot = Quaternion.identity; + zedManager.zedCamera.EstimateInitialPosition(ref initrot, ref initpos); + + transform.position = initpos + (initrot * Vector3.forward); + Quaternion newRot = Quaternion.LookRotation(initpos - transform.position, Vector3.up); + transform.eulerAngles = new Vector3(0, newRot.eulerAngles.y + 180, 0); + + } + else + { + transform.position = zedManager.OriginPosition + zedManager.OriginRotation * (Vector3.forward); + Quaternion newRot = Quaternion.LookRotation(zedManager.OriginPosition - transform.position, Vector3.up); + transform.eulerAngles = new Vector3(0, newRot.eulerAngles.y + 180, 0); + } + + //If we're going to know where the floor is, then make sure the object doesn't spawn in the floor if the user is looking down. + if(zedManager.estimateInitialPosition) + { + if (transform.position.y < 0.5f) transform.position = new Vector3(transform.position.x, 0.5f, transform.position.z); + } + } + + IEnumerator RepositionAfterZEDReady() + { + for (int i = 0; i < 50; i++) + { + print(zedManager.GetZedRootTansform().position); + yield return null; + } + + + } + + /// + /// 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/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs.meta new file mode 100644 index 0000000..1e8517c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Interactions/ZEDTransformController.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: df8cabfa5906efe4a9e15874c62acc33 +timeCreated: 1526029655 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Lighting.meta b/Assets/ZED/SDK/Helpers/Scripts/Lighting.meta new file mode 100644 index 0000000..f44f0dc --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Lighting.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f80a50d1ea813764fa0b16156b9e4183 +folderAsset: yes +timeCreated: 1509118368 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs b/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs new file mode 100644 index 0000000..f72acd3 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs @@ -0,0 +1,70 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +using System.Collections.Generic; +using UnityEngine; + +/// +/// 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 +{ + /// + /// List of all ZEDLights in the scene. + /// + [HideInInspector] + public static List s_lights = new List(); + + /// + /// Light component attached to this GameObject. + /// + [HideInInspector] + public Light cachedLight; + + /// + /// Interior cone of the spotlight, if the Light is a spotlight. + /// + [HideInInspector] + public float interiorCone = 0.1f; + + // Use this for initialization + void OnEnable() + { + if (!s_lights.Contains(this)) + { + s_lights.Add(this); + cachedLight = GetComponent(); + } + } + + void OnDisable() + { + if (s_lights != null) + { + s_lights.Remove(this); + } + } + + + /// + /// 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() + { + if (!cachedLight.enabled) + { + return false; + } + + if (cachedLight.range <= 0 || cachedLight.intensity <= 0) + { + return false; + } + + return true; + } +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs.meta new file mode 100644 index 0000000..af84ea4 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Lighting/ZEDLight.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fc0e4dfb527b99944a03710f713b764e +timeCreated: 1507141804 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/MR.meta b/Assets/ZED/SDK/Helpers/Scripts/MR.meta new file mode 100644 index 0000000..08b1060 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/MR.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 71f7272bff6c850439550247a33de9cd +folderAsset: yes +timeCreated: 1508143189 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs b/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs new file mode 100644 index 0000000..08e0e75 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs @@ -0,0 +1,46 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; + +/// +/// 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 +{ + /// + /// The scene's ZEDManager component, for getting the texture overlay. + /// + public ZEDManager manager; + + /// + /// Reference to the ZEDRenderingPlane that renders the left eye, so we can get its target RenderTexture. + /// + private ZEDRenderingPlane textureOverlayLeft; + + void Start() + { + UnityEngine.XR.XRSettings.showDeviceView = false; //Turn off default behavior. + } + + private void Update() + { + if (textureOverlayLeft == null && manager != null) + { + textureOverlayLeft = manager.GetLeftCameraTransform().GetComponent(); + } + } + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + if (textureOverlayLeft != null) + { + //Ignore source. Copy ZEDRenderingPlane's texture as the final image. + Graphics.Blit(textureOverlayLeft.target, destination); + } + } + +} \ No newline at end of file diff --git a/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs.meta new file mode 100644 index 0000000..3c35a04 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMirror.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 784475720e60ab84784f12e90dc1ce65 +timeCreated: 1508143191 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs b/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs new file mode 100644 index 0000000..03d0053 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs @@ -0,0 +1,867 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; +using System.Runtime.InteropServices; +using UnityEngine.VR; +using System.IO; + +/// +/// 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 +{ + #region DLL Calls + const string nameDll = sl.ZEDCommon.NameDLL; + [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); + + [DllImport(nameDll, EntryPoint = "dllz_compute_hmd_focal")] + private static extern float dllz_compute_hmd_focal(sl.Resolution r, float w, float h); + + /*****LATENCY CORRECTOR***/ + [DllImport(nameDll, EntryPoint = "dllz_latency_corrector_add_key_pose")] + private static extern void dllz_latency_corrector_add_key_pose(ref Vector3 translation, ref Quaternion rotation, ulong timeStamp); + + [DllImport(nameDll, EntryPoint = "dllz_latency_corrector_get_transform")] + private static extern int dllz_latency_corrector_get_transform(ulong timeStamp, bool useLatency,out Vector3 translation, out Quaternion rotation); + + [DllImport(nameDll, EntryPoint = "dllz_latency_corrector_initialize")] + private static extern void dllz_latency_corrector_initialize(int device); + + [DllImport(nameDll, EntryPoint = "dllz_latency_corrector_shutdown")] + private static extern void dllz_latency_corrector_shutdown(); + + /****ANTI DRIFT ***/ + [DllImport(nameDll, EntryPoint = "dllz_drift_corrector_initialize")] + public static extern void dllz_drift_corrector_initialize(); + + [DllImport(nameDll, EntryPoint = "dllz_drift_corrector_shutdown")] + public static extern void dllz_drift_corrector_shutdown(); + + [DllImport(nameDll, EntryPoint = "dllz_drift_corrector_get_tracking_data")] + public static extern void dllz_drift_corrector_get_tracking_data(ref TrackingData trackingData, ref Pose HMDTransform, ref Pose latencyCorrectorTransform, int hasValidTrackingPosition,bool checkDrift); + + [DllImport(nameDll, EntryPoint = "dllz_drift_corrector_set_calibration_transform")] + public static extern void dllz_drift_corrector_set_calibration_transform(ref Pose pose); + + [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 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 + { + public Vector3 translation; + public Quaternion rotation; + + public Pose(Vector3 t, Quaternion q) + { + translation = t; + rotation = q; + } + } + + /// + /// + /// + [StructLayout(LayoutKind.Sequential)] + public struct TrackingData + { + public Pose zedPathTransform; + public Pose zedWorldTransform; + public Pose offsetZedWorldTransform; + + public int trackingState; + } + /// + /// 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; + /// + /// 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 { + get { return hasVRDevice; } + } + + /// + /// The current latency pose - the pose the headset was at when the last ZED frame was captured (based on its timestamp). + /// + private Pose latencyPose; + + /// + /// 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; } + } + + /// + /// Whether the latency correction is ready. + /// + private bool latencyCorrectionReady = false; + + /// + /// Contains the last position computed by the anti-drift. + /// + public TrackingData trackingData = new TrackingData(); + + /// + /// 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"; + + /// + /// 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; + + /// + /// Cached property id for _MainTex. use the mainTexID property instead. + /// + private int? _maintexid; + /// + /// Property id for _MainTex, which is the main texture from the ZED. + /// + private int mainTexID + { + get + { + if (_maintexid == null) _maintexid = Shader.PropertyToID("_MainTex"); + return (int)_maintexid; + } + } + +#if UNITY_2017_OR_NEWER + List nodes = new List(); + + UnityEngine.VR.VRNodeState nodeState = new UnityEngine.VR.VRNodeState(); +#endif + private void Awake() + { + //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 = UnityEngine.XR.XRDevice.isPresent; + if (hasVRDevice) { + if (UnityEngine.XR.XRDevice.model.ToLower().Contains ("vive")) //Vive or Vive Pro + dllz_latency_corrector_initialize (0); + else if (UnityEngine.XR.XRDevice.model.ToLower().Contains ("oculus") || //Oculus Rift + UnityEngine.XR.XRDevice.model.ToLower().Contains("windows") || //Most WMR headsets + UnityEngine.XR.XRDevice.model.ToLower().Contains("visor") || //Dell Visor + UnityEngine.XR.XRDevice.model.ToLower().Contains("explorer")) //Lenovo Explorer + dllz_latency_corrector_initialize (1); + else if (UnityEngine.XR.XRDevice.model.ToLower().Contains ("windows")) //Windows MR through SteamVR Only (Beta) + dllz_latency_corrector_initialize (1); + + + dllz_drift_corrector_initialize (); + } + #if UNITY_2017_OR_NEWER + + nodeState.nodeType = VRNode.Head; + nodes.Add(nodeState); + #endif + } + + /// + /// 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 = UnityEngine.XR.XRDevice.isPresent; + + + //iterate until we found the ZED Manager parent... + Transform ObjParent = gameObject.transform; + int tries = 0; + while (manager == null && tries < 50) { + if (ObjParent!=null) + manager= ObjParent.GetComponent (); + if (manager == null && ObjParent!=null) + ObjParent = ObjParent.parent; + tries++; + } + + if (manager != null) { + manager.OnZEDReady += ZEDReady; + zedCamera = manager.zedCamera; + } else + return; + + leftScreen = ZEDEyeLeft.GetComponent(); + rightScreen = ZEDEyeRight.GetComponent(); + finalLeftEye = finalCameraLeft.GetComponent(); + finalRightEye = finalCameraRight.GetComponent(); + + rightMaterial = quadRight.GetComponent().material; + leftMaterial = quadLeft.GetComponent().material; + finalLeftEye.SetReplacementShader(leftMaterial.shader, ""); + finalRightEye.SetReplacementShader(rightMaterial.shader, ""); + + float plane_dist = (float)sl.Constant.PLANE_DISTANCE; + 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(); + + } + + /// + /// 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) + { + System.IntPtr p = dllz_compute_size_plane_with_gamma(resolution, perceptionDistance, eyeToZedDistance, planeDistance, HMDFocal, zedFocal); + + if (p == System.IntPtr.Zero) + { + return new Vector2(); + } + Vector2 parameters = (Vector2)Marshal.PtrToStructure(p, typeof(Vector2)); + return parameters; + + } + + /// + /// Compute the focal length of the HMD. + /// + /// Resolution of the headset's eye textures. + /// + public float ComputeFocal(sl.Resolution targetSize) + { + float focal_hmd = dllz_compute_hmd_focal(targetSize, finalLeftEye.projectionMatrix.m00,finalLeftEye.projectionMatrix.m11); + 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; //Estimating 10cm between your eye and physical location of the ZED Mini. + hasVRDevice = UnityEngine.XR.XRDevice.isPresent; + + if (hasVRDevice) { + sl.CalibrationParameters parameters = zedCamera.CalibrationParametersRectified; + + scaleFromZED = ComputeSizePlaneWithGamma (new sl.Resolution ((uint)zedCamera.ImageWidth, (uint)zedCamera.ImageHeight), + perception_distance, zed2eye_distance, offset.z, + ComputeFocal (new sl.Resolution ((uint)UnityEngine.XR.XRSettings.eyeTextureWidth, (uint)UnityEngine.XR.XRSettings.eyeTextureHeight)), + parameters.leftCam.fx); + + scale (quadLeft.gameObject, scaleFromZED); + scale (quadRight.gameObject, scaleFromZED); + } + ready = false; + + // If using Vive, change ZED's settings to compensate for different screen. + if (UnityEngine.XR.XRDevice.model.ToLower().Contains ("vive")) { + zedCamera.SetCameraSettings (sl.CAMERA_SETTINGS.CONTRAST, 3); + zedCamera.SetCameraSettings (sl.CAMERA_SETTINGS.SATURATION, 3); + } + + + //Set eye layers to respective eyes. They were each set to Both during the loading screen to avoid one eye going blank at some rotations. + finalLeftEye.stereoTargetEye = StereoTargetEyeMask.Left; + finalRightEye.stereoTargetEye = StereoTargetEyeMask.Right; + + /// 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 ideal for a proper AR passthrough experience. Recommended resolution is 1280x720."); + + zedReady = true; + + } + + public void OnEnable() + { + latencyCorrectionReady = false; + if (manager !=null) + manager.OnZEDReady += ZEDReady; + } + + public void OnDisable() + { + latencyCorrectionReady = false; + if (manager !=null) + manager.OnZEDReady -= ZEDReady; + } + + void OnGrab() + { + grabSucceeded = true; + } + + /// + /// Collects the position of the HMD with a timestamp, to be looked up later to correct for latency. + /// + public void CollectPose() + { + if (manager == null) + return; + + KeyPose k = new KeyPose(); + k.Orientation = UnityEngine.XR.InputTracking.GetLocalRotation(UnityEngine.XR.XRNode.Head); + k.Translation = UnityEngine.XR.InputTracking.GetLocalPosition(UnityEngine.XR.XRNode.Head); + if (manager.zedCamera.IsCameraReady) + { + k.Timestamp = manager.zedCamera.GetCurrentTimeStamp(); + if (k.Timestamp >= 0) + { + 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. + /// + /// 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); + } + + /// + /// 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 planes/canvases to the proper position after accounting for latency. + /// + public void UpdateRenderPlane() + { + if (manager == null) + return; + + if (!manager.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; + quadRight.localPosition = finalRightEye.transform.localPosition + r * (offset); + + } + + /// + /// 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() + { + if (manager == null) + return new Pose (); + + Transform tmpHMD = transform; + tmpHMD.position = UnityEngine.XR.InputTracking.GetLocalPosition(UnityEngine.XR.XRNode.Head); + tmpHMD.rotation = UnityEngine.XR.InputTracking.GetLocalRotation (UnityEngine.XR.XRNode.Head); + + Quaternion r = Quaternion.identity; + Vector3 t = Vector3.zero; + Pose const_offset = new Pose(t, r); + dllz_drift_corrector_set_calibration_const_offset_transform(ref const_offset); + + zedCamera.ResetTrackingWithOffset(tmpHMD.rotation,tmpHMD.position,HmdToZEDCalibration.rotation,HmdToZEDCalibration.translation); + + 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; + Vector3 latency_pos; + if (LatencyCorrector (out latency_rot, out latency_pos, cameraTimeStamp, true) == 1) { + latencyPose = new Pose (latency_pos, latency_rot); + latencyCorrectionReady = true; + } else + 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, bool setimuprior) + { + hasVRDevice = UnityEngine.XR.XRDevice.isPresent; + + Pose hmdTransform = new Pose(UnityEngine.XR.InputTracking.GetLocalPosition(UnityEngine.XR.XRNode.Head), UnityEngine.XR.InputTracking.GetLocalRotation(UnityEngine.XR.XRNode.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 && setimuprior == true) { + zedCamera.SetIMUOrientationPrior (ref latencyPose.rotation); + } + + dllz_drift_corrector_get_tracking_data (ref trackingData, ref hmdTransform, ref latencyPose, 0, true); + r = trackingData.offsetZedWorldTransform.rotation; + 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) //Make sure intermediate cameras are rendering to the quad's materials. + { + if (leftScreen.target != null && leftScreen.target.IsCreated()) + { + //leftMaterial.SetTexture("_MainTex", leftScreen.target); + leftMaterial.SetTexture(mainTexID, leftScreen.target); + ready = true; + } + else ready = false; + if (rightScreen.target != null && rightScreen.target.IsCreated()) + { + rightMaterial.SetTexture(mainTexID, rightScreen.target); + ready = true; + } + else ready = false; + } + + if (hasVRDevice) //Do nothing if we no longer have a HMD connected. + { + CollectPose (); //File the current HMD pose into the latency poses to reference later. + UpdateRenderPlane(); //Reposition the final quads based on the latency pose. + } + } + + + /// + /// 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) + { + if (cam == finalLeftEye || cam == finalRightEye) + { + + if ((!manager.IsZEDReady && manager.IsStereoRig)) + { + quadLeft.localRotation = UnityEngine.XR.InputTracking.GetLocalRotation(UnityEngine.XR.XRNode.Head); + quadLeft.localPosition = UnityEngine.XR.InputTracking.GetLocalPosition(UnityEngine.XR.XRNode.Head) + quadLeft.localRotation * offset; + + quadRight.localRotation = UnityEngine.XR.InputTracking.GetLocalRotation(UnityEngine.XR.XRNode.Head); + quadRight.localPosition = UnityEngine.XR.InputTracking.GetLocalPosition(UnityEngine.XR.XRNode.Head) + quadRight.localRotation * offset; + + } + } + } + + + /// + /// 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) + hmdtozedCalibration.rotation = Quaternion.identity; + hmdtozedCalibration.translation.x = 0.0315f;//-zedCamera.Baseline/2; + hmdtozedCalibration.translation.y = 0.0f; + hmdtozedCalibration.translation.z = 0.11f; + + + //if a calibration exists then load it + //should be in ProgramData/stereolabs/mr/calibration.ini + string folder = System.Environment.GetFolderPath (System.Environment.SpecialFolder.CommonApplicationData); + string specificFolder = Path.Combine (folder, @"Stereolabs\mr"); + calibrationFilePath = Path.Combine (specificFolder, calibrationFile); + + + // Check if folder exists and if not, create it + if (!Directory.Exists (specificFolder)) { + Directory.CreateDirectory (specificFolder); + } + + // Check if file exist and if not, create a default one + if (!ParseCalibrationFile (calibrationFilePath)) + CreateDefaultCalibrationFile (calibrationFilePath); + + // Set the calibration in mr processing + dllz_drift_corrector_set_calibration_transform (ref hmdtozedCalibration); + + // Create a file system watcher for online modifications + CreateFileWatcher (specificFolder); + } + } + + /// + /// 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. + FileSystemWatcher watcher = new FileSystemWatcher(); + watcher.Path = folder; + /* 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; + // Only watch text files. + watcher.Filter = calibrationFile; + + // Add event handlers. + watcher.Changed += new FileSystemEventHandler(OnChanged); + + // Begin watching. + watcher.EnableRaisingEvents = true; + } + + /// + /// 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); + 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. + 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. + 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"; + string ty = "ty=" + hmdtozedCalibration.translation.y.ToString (System.Globalization.CultureInfo.InvariantCulture) + " //Translation y"; + string tz = "tz=" + hmdtozedCalibration.translation.z.ToString (System.Globalization.CultureInfo.InvariantCulture) + " //Translation z"; + string rx = "rx=" + hmdtozedCalibration.rotation.x.ToString (System.Globalization.CultureInfo.InvariantCulture) + " //Quaternion x"; + string ry = "ry=" + hmdtozedCalibration.rotation.y.ToString (System.Globalization.CultureInfo.InvariantCulture) + " //Quaternion y"; + string rz = "rz=" + hmdtozedCalibration.rotation.z.ToString (System.Globalization.CultureInfo.InvariantCulture) + " //Quaternion z"; + string rw = "rw=" + hmdtozedCalibration.rotation.w.ToString (System.Globalization.CultureInfo.InvariantCulture) + " //Quaternion w"; + + file.WriteLine (node); + file.WriteLine (tx); + file.WriteLine (ty); + file.WriteLine (tz); + file.WriteLine (rx); + file.WriteLine (ry); + file.WriteLine (rz); + file.WriteLine (rw); + + file.Close (); + } + } + + /// + /// 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; + + string[] lines = null; + try + { + lines = System.IO.File.ReadAllLines(path); + } + catch (System.Exception) + { + return false; + } + 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; + hmdtozedCalibration.translation.z = 0.115f; + + foreach (string line in lines) + { + string[] splittedLine = line.Split('='); + + if (splittedLine != null && splittedLine.Length >= 2) + { + string key = splittedLine[0]; + string field = splittedLine[1].Split(' ')[0]; + + if (key == "tx") + { + hmdtozedCalibration.translation.x = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "ty") + { + hmdtozedCalibration.translation.y = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "tz") + { + hmdtozedCalibration.translation.z = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "rx") + { + hmdtozedCalibration.rotation.x = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "ry") + { + hmdtozedCalibration.rotation.y = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "rz") + { + hmdtozedCalibration.rotation.z = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + else if (key == "rw") + { + hmdtozedCalibration.rotation.w = float.Parse(field, System.Globalization.CultureInfo.InvariantCulture); + } + } + } + + + //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/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs.meta new file mode 100644 index 0000000..e5d3d35 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/MR/ZEDMixedRealityPlugin.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c8e97796473acba4baba8b73c106fe7b +timeCreated: 1515074494 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection.meta b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection.meta new file mode 100644 index 0000000..fb51983 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c7472f0c0e0386c4081a43015ee6dea2 +folderAsset: yes +timeCreated: 1543443412 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs new file mode 100644 index 0000000..31f43ca --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs @@ -0,0 +1,665 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; +using System.Collections.Generic; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +/// +/// 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 +{ + /// + /// GameObject all planes are parented to. Created at runtime, called '[ZED Planes]' in Hierarchy. + /// + private GameObject holder; + + /// + /// 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; } + } + + /// + /// 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; + + /// + /// 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 in the Scene view using ZEDPlaneRenderer. Usually the same as isVisibleInSceneOption. + /// + public static bool isSceneDisplay = true; + + /// + /// Whether we're displaying the planes in the Game view using ZEDPlaneRenderer. Usually the same as isVisibleInGameOption. + /// Used by ZEDRenderingPlane to know if it should draw the meshes in its OnRenderImage() method. + /// + public static bool isGameDisplay = false; + + + /// + /// Whether the planes can collide with virtual objects (with colliders). Changing this enables/disables + /// mesh colliders on all new and existing planes. + /// + public bool planesHavePhysics + { + get + { + return addPhysicsOption; + } + set + { + if (addPhysicsOption != value) + { + willUpdatePhysics = true; + addPhysicsOption = value; + } + } + } + /// + /// Whether the planes can collide with virtual objects (with colliders). + /// To update publicly or at runtime, use planesHavePhysics instead. + /// + [SerializeField] + private bool addPhysicsOption = true; + /// + /// If true, existing planes will have their colliders updated + /// based on addPhhysicsOption in the next Update() step. + /// + private bool willUpdatePhysics = false; + + /// + /// Whether the planes are drawn. Changing this setting enables/disables the plane's MeshRenderers. + /// Note that if disabled, planes will not be drawn in the Game view regardless of the planesVisibleInGame setting. + /// + public bool planesVisibleInScene + { + get + { + return isVisibleInSceneOption; + } + set + { + if (value != isVisibleInSceneOption) + { + + isVisibleInSceneOption = value; + willUpdateSceneVisibility = true; + } + } + } + /// + /// Whether the planes are drawn. + /// To update publicly or at runtime, use planesVisibleInScene instead. + /// + [SerializeField] + private bool isVisibleInSceneOption = true; + /// + /// If true, existing planes will have their visibility updated + /// based on isVisibleInSceneOption in the next Update() step. + /// + private bool willUpdateSceneVisibility = true; + + /// + /// Whether the planes are drawn in the ZED's final output, viewable in Unity's Game window or a build. + /// + public bool planesVisibleInGame + { + get + { + return isVisibleInGameOption; + } + set + { + if (value != isVisibleInGameOption) + { + isVisibleInGameOption = value; + willUpdateGameVisibility = true; + } + } + } + /// + /// Whether the planes are drawn in the ZED's final output, viewable in Unity's Game window or a build. + /// To update publicly or at runtime, use planesVisibleInGame instead. + /// + [SerializeField] + private bool isVisibleInGameOption = true; + /// + /// If true, existing planes will have their in-game visibility updated + /// based on isVisibleInGameOption in the next Update() step. + /// + private bool willUpdateGameVisibility = 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. + + /// + /// 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; } + } + + /// + /// Assign references, create the holder gameobject, and other misc. initialization. + /// + private void Start() + { + //Create a holder for all the planes + holder = new GameObject(); + holder.name = "[ZED Planes]"; + holder.transform.parent = this.transform; + holder.transform.position = Vector3.zero; + holder.transform.rotation = Quaternion.identity; + StaticBatchingUtility.Combine(holder); + + //initialize Vertices/Triangles with enough length + planeMeshVertices = new Vector3[65000]; + planeMeshTriangles = new int[65000]; + + //floorPlaneGO = holder.AddComponent (); + hitPlaneList = new List(); + } + + public void OnDisable() + { + foreach (Transform child in holder.transform) + { + Destroy(child.gameObject); + + Destroy(holder); + } + } + + /// + /// 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). + /// Source triangles (in camera space). + /// Dst vertices (in world space). + /// Dst triangles (in world space). + /// Number of vertices. + /// Number of triangles. + private void TransformCameraToLocalMesh(Transform camera, Vector3[] srcVertices, int[] srcTriangles, Vector3[] dstVertices, int[] dstTriangles, int numVertices, int numTriangles, Vector3 centerpos) + { + if (numVertices == 0 || numTriangles == 0) + return; //Plane is empty. + + System.Array.Copy(srcVertices, dstVertices, numVertices); + System.Buffer.BlockCopy(srcTriangles, 0, dstTriangles, 0, numTriangles * sizeof(int)); + + for (int i = 0; i < numVertices; i++) + { + dstVertices[i] -= centerpos; + dstVertices[i] = camera.transform.rotation * dstVertices[i]; + } + + } + + /// + /// 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. + /// Uses the first available ZEDManager in the scene. + /// + /// true, if floor plane was detected, false otherwise. + public bool DetectFloorPlane(bool auto) + { + //Find the first available ZEDManager. + List managers = ZEDManager.GetInstances(); + if (managers.Count == 0) return false; //No ZEDManager to use. + else return DetectFloorPlane(managers[0], 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. + /// Note that this can't be called the first frame the ZED is ready. Use a coroutine to wait one frame, + /// or until ZEDManager.isZEDReady is true. + /// + /// true, if floor plane was detected, false otherwise. + public bool DetectFloorPlane(ZEDManager manager, bool auto) + { + if (!manager.IsZEDReady) + return false; //Do nothing if the ZED isn't finished initializing. + + sl.ZEDCamera zedcam = manager.zedCamera; + Camera cam = manager.GetMainCamera(); + + ZEDPlaneGameObject.PlaneData plane = new ZEDPlaneGameObject.PlaneData(); + 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) + { + Vector3[] worldPlaneVertices = new Vector3[numVertices]; + int[] worldPlaneTriangles = new int[numTriangles]; + TransformCameraToLocalMesh(cam.transform, planeMeshVertices, planeMeshTriangles, worldPlaneVertices, worldPlaneTriangles, numVertices, numTriangles, plane.PlaneCenter); + + hasDetectedFloor = true; + + if (!floorPlaneGO) + { //Make the GameObject. + floorPlaneGO = new GameObject("Floor Plane"); + floorPlaneGO.transform.SetParent(holder.transform); + } + + 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. + floorPlaneGO.transform.position = cam.transform.position; //Add the camera's world position + floorPlaneGO.transform.position += cam.transform.rotation * plane.PlaneCenter; //Add the center of the plane + + if (!floorPlane) //Add a new ZEDPlaneGameObject to the floor plane if it doesn't already exist. + { + floorPlane = floorPlaneGO.AddComponent(); + } + + + if (!floorPlane.IsCreated) //Call ZEDPlaneGameObject.Create() on the floor ZEDPlaneGameObject if it hasn't yet been run. + { + if (overrideMaterial != null) floorPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, 0, overrideMaterial); + else floorPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, 0); + floorPlane.SetPhysics(addPhysicsOption); + } + else //Update the ZEDPlaneGameObject with the new plane's data. + { + floorPlane.UpdateFloorPlane(!auto, plane, worldPlaneVertices, worldPlaneTriangles, overrideMaterial); + floorPlane.SetPhysics(addPhysicsOption); + + } + return true; + } + } + + return false; + } + + /// + /// Detects the plane around screen-space coordinates specified. + /// Uses the first available ZEDManager in the scene. + /// + /// true, if plane at hit was detected, false otherwise. + /// Position of the pixel in screen space (2D). + public bool DetectPlaneAtHit(Vector2 screenPos) + { + //Find the first available ZEDManager. + List managers = ZEDManager.GetInstances(); + if (managers.Count == 0) return false; //No ZEDManager to use. + else if (managers.Count > 1) //They're using multiple cameras but using the first available manager. Not ideal. + { + Debug.LogWarning("Using DetectPlaneAtHit without specifying a manager while multiple ZEDManagers are present. " + + "This can cause planes to be calculated by the wrong camera. It's recommended to use the (ZEDManager, Vector2) overload."); + } + return DetectPlaneAtHit(managers[0], screenPos); + } + + /// + /// 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). + public bool DetectPlaneAtHit(ZEDManager manager, Vector2 screenPos) + { + if (!manager.IsZEDReady) + return false; //Do nothing if the ZED isn't finished initializing. + + sl.ZEDCamera zedcam = manager.zedCamera; + Camera cam = manager.GetMainCamera(); + + 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(); //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(cam.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. + newhitGO.transform.position = cam.transform.position; //Add the camera's world position + newhitGO.transform.position += cam.transform.rotation * plane.PlaneCenter; //Add the center of the plane + + ZEDPlaneGameObject hitPlane = newhitGO.AddComponent(); + + if (overrideMaterial != null) hitPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, planeHitCount + 1, overrideMaterial); + else hitPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, planeHitCount + 1); + + hitPlane.SetPhysics(addPhysicsOption); + //hitPlane.SetVisible(isVisibleInSceneOption); + hitPlaneList.Add(hitPlane); + planeHitCount++; + return true; + } + } + + return false; + + } + + + /// + /// Check if the screen was clicked. If so, check for a plane where the click happened using DetectPlaneAtHit(). + /// + void Update() + { + //Detect hits when you click on the screen. + if (Input.GetMouseButtonDown(0)) + { + Vector2 ScreenPosition = Input.mousePosition; + + List managers = ZEDManager.GetInstances(); + if (managers.Count == 1) //There's only one ZEDManager, so use that one. + DetectPlaneAtHit(managers[0], ScreenPosition); + else if (managers.Count > 1) + { + //There are at least two ZEDManagers rendering. Find the one that's likely the last to render, so it's the one the user clicked on. + float highestdepth = Mathf.NegativeInfinity; + ZEDManager highestmanager = managers[0]; + foreach (ZEDManager manager in managers) + { + float depth = manager.GetMainCamera().depth; + if (depth >= highestdepth) + { + highestdepth = depth; + highestmanager = manager; + } + } + + DetectPlaneAtHit(highestmanager, ScreenPosition); + } + } + + //Update plane physics if needed. + if (willUpdatePhysics) + { + if (floorPlane != null && floorPlane.IsCreated) + { + floorPlane.SetPhysics(addPhysicsOption); + } + if (hitPlaneList != null) + { + foreach (ZEDPlaneGameObject c in hitPlaneList) + { + if (c.IsCreated) + c.SetPhysics(addPhysicsOption); + } + } + willUpdatePhysics = false; + } + + //Update visibility if needed. + if (willUpdateSceneVisibility) + { + /*if (floorPlane != null && floorPlane.IsCreated) + { + floorPlane.SetVisible(isVisibleInSceneOption); + } + if (hitPlaneList != null) + { + foreach (ZEDPlaneGameObject c in hitPlaneList) + { + c.SetVisible(isVisibleInSceneOption); + } + }*/ + SwitchSceneDisplay(); + willUpdateSceneVisibility = false; + } + + //Update in-game visibility if needed. + if (willUpdateGameVisibility) + { + SwitchGameDisplay(); + willUpdateGameVisibility = false; + } + + } + + /// + /// Switches the isGameDisplay setting, used to know if planes should be rendered to the Scene window. + /// + public void SwitchSceneDisplay() + { + isSceneDisplay = isVisibleInSceneOption; + } + + /// + /// Switches the isGameDisplay setting, used to know if planes should be rendered to the Game window. + /// + public void SwitchGameDisplay() + { + isGameDisplay = 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) + { + floorPlane.SetPhysics(addPhysicsOption); + + //floorPlane.SetVisible(isVisibleInSceneOption); + } + + if (hitPlaneList != null) + foreach (ZEDPlaneGameObject c in hitPlaneList) + { + if (c.IsCreated) + c.SetPhysics(addPhysicsOption); + + //c.SetVisible(isVisibleInSceneOption); + } + + SwitchSceneDisplay(); + SwitchGameDisplay(); + } + + +#endif + +} + + + +#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) }; + + /// + /// 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; + + + private ZEDPlaneDetectionManager Target + { + get { return (ZEDPlaneDetectionManager)target; } + } + + public void OnEnable() + { + //Assign the serialized properties to their appropriate properties. + planeDetector = (ZEDPlaneDetectionManager)target; + addPhysicsOption = serializedObject.FindProperty("addPhysicsOption"); + isVisibleInSceneOption = serializedObject.FindProperty("isVisibleInSceneOption"); + isVisibleInGameOption = serializedObject.FindProperty("isVisibleInGameOption"); + overrideMaterialOption = serializedObject.FindProperty("overrideMaterial"); + } + + public override void OnInspectorGUI() + { + //bool cameraIsReady = planeDetector.Manager != null ? planeDetector.Manager.zedCamera.IsCameraReady : false; + + serializedObject.Update(); + + GUILayout.Space(20); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label("Detection Parameters", EditorStyles.boldLabel); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + //GUI.enabled = cameraIsReady; + EditorGUILayout.BeginHorizontal(); + 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)) + { + planeDetector.DetectFloorPlane(false); + } + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + GUI.enabled = true; + GUILayout.Space(20); + EditorGUILayout.BeginHorizontal(); + GUILayout.Label("Visualization", EditorStyles.boldLabel); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + 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 Game view."); + isVisibleInSceneOption.boolValue = EditorGUILayout.Toggle(visiblescenelabel, isVisibleInSceneOption.boolValue); + +#if !UNITY_2018_1_OR_NEWER + if (!isVisibleInSceneOption.boolValue) + { + //Older Unity versions have a bug that will spam errors if Visible In Scene is disabled. Warn the user. + GUIStyle warningmessagestyle = new GUIStyle(EditorStyles.label); + warningmessagestyle.normal.textColor = Color.gray; + warningmessagestyle.wordWrap = true; + warningmessagestyle.fontSize = 9; + + string warningtext = "Warning: Disabling Visible in Scene causes Unity versions 2017 and lower to spam error messages. This is due to a Unity bug and does not effect the scene."; + Rect labelrect = GUILayoutUtility.GetRect(new GUIContent(warningtext, ""), warningmessagestyle); + EditorGUI.LabelField(labelrect, warningtext, warningmessagestyle); + } +#endif + + isVisibleInGameOption.boolValue = EditorGUILayout.Toggle(visiblegamelabel, isVisibleInGameOption.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); + + + planeDetector.SwitchGameDisplay(); + GUILayout.Space(20); + GUI.enabled = true; + EditorGUILayout.BeginHorizontal(); + GUILayout.Label("Physics", EditorStyles.boldLabel); + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + GUIContent physicslabel = new GUIContent("Collisions", "Whether the planes can be collided with using physics."); + addPhysicsOption.boolValue = EditorGUILayout.Toggle(physicslabel, addPhysicsOption.boolValue); + + + serializedObject.ApplyModifiedProperties(); //Applies all changes to serializedproperties to the actual properties they're connected to. + + //if (!cameraIsReady) Repaint(); + Repaint(); + + } +} + + +#endif diff --git a/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs.meta new file mode 100644 index 0000000..06bcd32 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneDetectionManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ba700bf1e7ba50c42a63a0d43378e2a1 +timeCreated: 1520954455 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs new file mode 100644 index 0000000..afea2b8 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs @@ -0,0 +1,465 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using System.Collections.Generic; +using UnityEngine; +using System.Threading; +using System.Runtime.InteropServices; + +/// +/// 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 +{ + /// + /// 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 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 + { + return gameObject.transform.position; + } + } + + /// + /// The MeshRenderer attached to this object. + /// + MeshRenderer rend; + + /// + /// Enabled state of the attached Renderer prior to Unity's rendering stage. + /// Used so that manually disabling the object's MeshRenderer won't be undone by this script. + /// + private bool lastRenderState = true; + + /// + /// 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 MeshFilter to render the mesh + MeshFilter mf = gameObject.GetComponent(); + if (mf == null) + mf = gameObject.AddComponent(); + + //Eliminate superfluous vertices. + int highestvertindex = 0; + for (int i = 0; i < triangles.Length; i++) + { + if (triangles[i] > highestvertindex) highestvertindex = triangles[i]; + } + System.Array.Resize(ref vertices, highestvertindex + 1); + + + //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++) + { + Vector3 upwardcoords = rotatetobackward * (vertices[i] + worldCenter); + 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; + mf.mesh.uv = uvs; + mf.mesh.RecalculateNormals(); + mf.mesh.RecalculateBounds(); + + //Get the MeshRenderer and set properties. + rend = gameObject.GetComponent(); + if (rend == null) + rend = gameObject.AddComponent(); + rend.material = rendermaterial; + + //Turn off light and shadow effects, as the planes are meant to highlight a real-world object, not be a distinct object. + rend.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + rend.receiveShadows = false; + rend.enabled = true; + rend.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; + rend.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; + + //Get the MeshCollider and apply the new mesh to it. + MeshCollider mc = gameObject.GetComponent(); + if (mc == null) + mc = gameObject.AddComponent(); + + // Set the mesh for the collider. + mc.sharedMesh = mf.mesh; + + lastRenderState = true; + + } + + /// + /// Create the plane as a GameObject, and fills the internal PlaneData structure for future access. + /// + /// 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(Camera cam,PlaneData plane, Vector3[] vertices, int[] triangles, int opt_count) + { + Create(cam,plane, vertices, triangles, opt_count, GetDefaultMaterial(plane.Type)); + } + + /// + /// Create the plane as a GameObject with a custom material, and fills the internal PlaneData structure for future access. + /// + /// 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(Camera cam,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; + planeData.PlaneCenter = plane.PlaneCenter; + planeData.PlaneTransformPosition = plane.PlaneTransformPosition; + planeData.PlaneTransformOrientation = plane.PlaneTransformOrientation; + planeData.PlaneEquation = plane.PlaneEquation; + planeData.Extents = plane.Extents; + planeData.BoundsSize = plane.BoundsSize; + planeData.Bounds = new Vector3[plane.BoundsSize]; + System.Array.Copy (plane.Bounds, planeData.Bounds, plane.BoundsSize); + + //Calculate the world space normal. + Camera leftCamera = cam; + worldNormal = cam.transform.TransformDirection(planeData.PlaneNormal); + + //Create the MeshCollider. + gameObject.AddComponent().sharedMesh = null; + + if (plane.Type != PLANE_TYPE.FLOOR) //Give it a name. + gameObject.name = "Hit Plane " + opt_count; + else + gameObject.name = "Floor Plane"; + + + gameObject.layer = 12;//sl.ZEDCamera.TagOneObject; + + SetComponents(plane, vertices, triangles, rendermaterial); + + isCreated = true; + + //Subscribe to events that let you govern visibility in the scene and game. + Camera.onPreCull += PreCull; + Camera.onPostRender += PostRender; + } + + /// + /// 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 + /// 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) + { + bool need_update = false; + + 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; + else + { + Mesh tmp = new Mesh(); + tmp.vertices = vertices; + tmp.SetTriangles(triangles, 0, false); + tmp.RecalculateBounds(); + + Bounds tmpNBnds = tmp.bounds; + MeshFilter mf = gameObject.GetComponent(); + + if ((tmpNBnds.Contains(mf.mesh.bounds.min) && tmpNBnds.Contains(mf.mesh.bounds.max)) || (tmpNBnds.size.x * tmpNBnds.size.y > 1.1 * mf.mesh.bounds.size.x * mf.mesh.bounds.size.y)) + need_update = true; + + tmp.Clear(); + } + + } + else //Force mode. Update the mesh regardless of the existing mesh. + need_update = true; + + if (need_update) + SetComponents(plane, vertices, triangles, gameObject.GetComponent().material); + + + MeshRenderer mr = gameObject.GetComponent(); + if (mr != null) + { + if (rendermaterial != null) + { + mr.material = rendermaterial; + } + else + { + mr.material = GetDefaultMaterial(plane.Type); + } + } + + return need_update; + + } + + + + /// + /// Enable/disable the MeshCollider component to turn on/off collisions. + /// + /// If set to true, collisions will be enabled. + public void SetPhysics(bool c) + { + MeshCollider mc = gameObject.GetComponent(); + if (mc != null) + mc.enabled = c; + } + + /// + /// Enable/disable the MeshRenderer component to turn on/off visibility. + /// + /// If set to true c. + public void SetVisible(bool c) + { + MeshRenderer mr = gameObject.GetComponent(); + if (mr != null) + mr.enabled = c; + } + + /// + /// Gets the size of the bounding rect that fits the plane (aka 'extents'). + /// + /// The scale. + public Vector2 GetScale() + { + return planeData.Extents; + } + + /// + /// Returns the bounds of the plane from the MeshFilter. + /// + /// + public Bounds GetBounds() + { + MeshFilter mf = gameObject.GetComponent(); + if (mf != null) + return mf.mesh.bounds; + else + return new Bounds(gameObject.transform.position, Vector3.zero); + } + + /// + /// Gets the minimum distance to plane boundaries of a given 3D point (in world space) + /// + /// The minimum distance to boundaries. + /// World position. + public float getMinimumDistanceToBoundaries(Camera cam, Vector3 worldPosition,out Vector3 minimumBoundsPosition) + { + + Camera leftCamera = cam; + float minimal_distance = ZEDSupportFunctions.DistancePointLine (worldPosition, leftCamera.transform.TransformPoint(planeData.Bounds [0]), leftCamera.transform.TransformPoint(planeData.Bounds [1])); + + Vector3 BestFoundPoint = new Vector3(0.0f,0.0f,0.0f); + if (planeData.BoundsSize > 2) { + for (int i = 1; i < planeData.BoundsSize - 1; i++) { + float currentDistance = ZEDSupportFunctions.DistancePointLine (worldPosition, leftCamera.transform.TransformPoint(planeData.Bounds [i]), leftCamera.transform.TransformPoint(planeData.Bounds [i + 1])); + if (currentDistance < minimal_distance) { + minimal_distance = currentDistance; + BestFoundPoint = ZEDSupportFunctions.ProjectPointLine(worldPosition,leftCamera.transform.TransformPoint(planeData.Bounds[i]),leftCamera.transform.TransformPoint(planeData.Bounds[i+1])); + } + } + } + + minimumBoundsPosition = BestFoundPoint; + return minimal_distance; + } + + + /// + /// Determines whether this floor plane is visible by any camera. + /// + /// true if this instance is floor plane visible; otherwise, false. + 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 + Material defaultmaterial = new Material(Resources.Load("Materials/PlaneDetection/Mat_ZED_Geometry_WirePlane") as Material); + switch (type) + { + case PLANE_TYPE.FLOOR: + //Floor planes are blue + defaultmaterial.SetColor("_WireColor", new Color(44.0f / 255.0f, 157.0f / 255.0f, 222.0f / 255.0f, 174.0f / 255.0f)); + break; + case PLANE_TYPE.HIT_HORIZONTAL : + case PLANE_TYPE.HIT_VERTICAL : + case PLANE_TYPE.HIT_UNKNOWN : + // Hit planes are pink + defaultmaterial.SetColor("_WireColor", new Color(221.0f / 255.0f, 20.0f / 255.0f, 149.0f / 255.0f, 174.0f / 255.0f)); + break; + + default: + //Misc. planes are white + defaultmaterial.SetColor("_WireColor", new Color(1, 1, 1, 174.0f / 255.0f)); + break; + } + + return defaultmaterial; + } + + /// + /// Disables the MeshRenderer object for rendering a single camera, depending on display settings in ZEDPlaneDetectionManager. + /// + /// + private void PreCull(Camera currentcam) + { + lastRenderState = rend.enabled; + if (!rend.enabled) return; //We weren't going to render this object anyway, so skip the rest of the logic. + + if (currentcam.name.ToLower().Contains("scenecamera")) + { + rend.enabled = ZEDPlaneDetectionManager.isSceneDisplay; + + } + else + { + rend.enabled = ZEDPlaneDetectionManager.isGameDisplay; + } + + } + + /// + /// Re-enables the MeshRenderer after PreCull may disable it each time a camera renders. + /// + /// + private void PostRender(Camera currentcam) + { + rend.enabled = lastRenderState; + } + + private void OnDestroy() + { + Camera.onPreCull -= PreCull; + Camera.onPostRender -= PostRender; + } +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs.meta new file mode 100644 index 0000000..ee5bf32 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/PlaneDetection/ZEDPlaneGameObject.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a3a0891a165a9ca448139d98884ebe03 +timeCreated: 1520959940 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping.meta b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping.meta new file mode 100644 index 0000000..63a08ad --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 062666f54381c92418ab49c5bdc7b797 +folderAsset: yes +timeCreated: 1507561184 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs new file mode 100644 index 0000000..7507856 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs @@ -0,0 +1,143 @@ + +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; + +/// +/// 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 +{ + + private ZEDManager zedManager = null; + /// + /// Reference to the hidden camera we create at runtime. + /// + private Camera cam; + + /// + /// Target texture of the rendering done by the new camera. + /// + private RenderTexture meshTex; + + /// + /// Checks if the spatial mapping has started. + /// + private bool hasStarted = false; + + /// + /// Checks if the mesh requested is textured. If so, deativate the wireframe. + /// + public bool isTextured = false; + + /// + /// Shader used to render the wireframe. Normally Mat_ZED_Wireframe_Video_Overlay. + /// + private Shader shaderWireframe; + + /// + /// Reference to the ZEDRenderingPlane component of the camera we copy. + /// + private ZEDRenderingPlane renderingPlane; + + /// + /// Create the Mesh Rendering pipe + /// + public void Create() + { + + Transform ObjParent = gameObject.transform; + int tries = 0; + while (zedManager == null && tries<5) { + if (ObjParent!=null) + zedManager= ObjParent.GetComponent (); + if (zedManager == null && ObjParent!=null) + ObjParent = ObjParent.parent; + tries++; + } + + if (zedManager == null) { + return; + } + + //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.HideInHierarchy;//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 (zedManager.zedCamera.IsCameraReady) + { + meshTex = new RenderTexture(zedManager.zedCamera.ImageWidth, zedManager.zedCamera.ImageHeight, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default); + meshTex.Create(); + } + + //Set the camera's parameters. + cam.enabled = false; + cam.cullingMask = (1 << zedManager.zedCamera.TagOneObject); //Layer set aside for planes and spatial mapping meshes. + cam.targetTexture = meshTex; + cam.nearClipPlane = 0.1f; + cam.farClipPlane = 500.0f; + cam.fieldOfView = zedManager.zedCamera.GetFOV() * Mathf.Rad2Deg; + cam.projectionMatrix = zedManager.zedCamera.Projection; + cam.backgroundColor = new Color(0, 0, 0, 0); + cam.clearFlags = CameraClearFlags.Color; + cam.renderingPath = RenderingPath.VertexLit; + cam.depth = 0; + cam.depthTextureMode = DepthTextureMode.None; + + #if UNITY_5_6_OR_NEWER + cam.allowMSAA = false; + cam.allowHDR = false; + #endif + cam.useOcclusionCulling = false; + + shaderWireframe = (Resources.Load("Materials/SpatialMapping/Mat_ZED_Wireframe_Video_Overlay") as Material).shader; + + //Set the ZEDRenderingPlane blend texture to the one the new camera renders to. + renderingPlane = GetComponent(); + renderingPlane.SetTextureOverlayMapping(meshTex); + hasStarted = true; + } + + /// + /// Unsubscribes from relevant events. + /// + private void OnDisable() + { + hasStarted = false; + } + + /// + /// Renders the plane each frame, before cameras normally update, so the RenderTexture is ready to be blended. + /// + void Update() + { + if (zedManager!=null) { + if (zedManager.IsSpatialMappingDisplay && hasStarted) { + cam.enabled = true; + GL.wireframe = true; + cam.RenderWithShader (shaderWireframe, "RenderType"); + GL.wireframe = false; + cam.enabled = false; + } + } + } + + /// + /// Releases the target RenderTexture when the application quits. + /// + private void OnApplicationQuit() + { + if (meshTex != null && meshTex.IsCreated()) + { + meshTex.Release(); + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs.meta new file mode 100644 index 0000000..f4c941a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDMeshRenderer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7d85588c98bca724daef97a2193ce4b3 +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs new file mode 100644 index 0000000..896aef8 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs @@ -0,0 +1,1643 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using System.Collections.Generic; +using UnityEngine; +using System.Threading; +using System.Text; +using System; + +/// +/// 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 ZEDSpatialMapping. The scan is made of multiple chunks. + /// + public struct Chunk + { + /// + /// Reference to the GameObject that holds the MeshFilter. + /// + public GameObject o; + /// + /// Dynamic mesh data that will change throughout the spatial mapping. + /// + public ProceduralMesh proceduralMesh; + /// + /// Final mesh, assigned to once the spatial mapping is over and done processing. + /// + public Mesh mesh; + } + + /// + /// Structure to contain a temporary buffer that holds triangles and vertices. + /// + public struct ProceduralMesh + { + /// + /// List of vertex indexes that make up triangles. + /// + public int[] triangles; + /// + /// List of vertices in the mesh. + /// + public Vector3[] vertices; + /// + /// MeshFilter of a GameObject that holds the chunk this ProceduralMesh represents. + /// + public MeshFilter mesh; + }; + + + + /// + /// Spatial mapping depth resolution presets. + /// + public enum RESOLUTION + { + /// + /// Create detailed geometry. Requires lots of memory. + /// + HIGH, + /// + /// Small variations in the geometry will disappear. Useful for large objects. + /// + /// + MEDIUM, + /// + /// Keeps only large variations of the geometry. Useful for outdoors. + /// + LOW + } + + /// + /// Spatial mapping depth range presets. + /// + public enum RANGE + { + /// + /// Geometry within 3.5 meters of the camera will be mapped. + /// + NEAR, + /// + /// Geometry within 5 meters of the camera will be mapped. + /// + MEDIUM, + /// + /// Objects as far as 10 meters away are mapped. Useful for outdoors. + /// + FAR + } + + /// + /// Current instance of the ZED Camera. + /// + private sl.ZEDCamera zedCamera; + + /// + /// Instance of an internal helper class for low-level mesh processing. + /// + 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; + + /// + /// True when RequestSaveMesh has been called, so that ongoing threads know to stop and save the mesh + /// when everything is finished processing. + /// + private bool saveRequested = false; + /// + /// Where the new mesh will be saved. Should end in .obj. + /// If textured, a .mtl (material) file and .png file will appear in the same folder with the same base filename. + /// + private string savePath = "Assets/ZEDMesh.obj"; + +#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, so that new triangles are copied into the dynamic mesh starting at the correct index. + /// + private int trianglesOffsetLastFrame; + /// + /// 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, so that new UV coordinates are copied into the dynamic mesh starting at the correct index. + /// + private int uvsOffsetLastFrame; + /// + /// Index of the mesh that was updated last frame. + /// + private int indexLastFrame; + /// + /// Flag set to true if there were meshes what weren't completely updated last frame due to lack of time. + /// + private bool remainMeshes = false; + + /// + /// The user has requested to stop spatial mapping. + /// + private bool stopWanted = false; + + /// + /// Whether the mesh is in the filtering stage of processing. + /// + private bool isFiltering = false; + + /// + /// Whether the filtering stage of the mesh's processing has started and finished. + /// + private bool isFilteringOver = false; + + /// + /// Whether the update thread will stop running. + /// + private bool stopRunning = false; + + /// + /// 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 that causes spatial mapping to pause when true. Use SwitchPauseState() to change. + /// + private bool pause = false; + + /// + /// Returns true if spatial mapping has been paused. This can be set to true even if spatial mapping isn't running. + /// + public bool IsPaused + { + get { return pause; } + } + + /// + /// Whether scanned meshes are visible or not. + /// + public bool display = false; + + /// + /// State of the scanning during its initialization. Used to know if it has started successfully. + /// + private sl.ERROR_CODE scanningInitState; + + /// + /// 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 event OnNewMesh OnMeshUpdate; + + /// + /// Delegate for OnMeshReady, which is called when spatial mapping has finished. + /// + public delegate void OnSpatialMappingEnded(); + /// + /// Event called when spatial mapping has finished. + /// + public event OnSpatialMappingEnded OnMeshReady; + + /// + /// Delegate for OnMeshStarted, which is called when spatial mapping has started. + /// + public delegate void OnSpatialMappingStarted(); + /// + /// Event called when spatial mapping has started. + /// + public event OnSpatialMappingStarted OnMeshStarted; + + /// + /// GameObject to which every chunk of the mesh is parented. Represents the scanned mesh in Unity's Hierarchy. + /// + private GameObject holder = null; + + /**** Threading Variables ****/ + /// + /// True if the mesh has been updated, and needs to be processed. + /// + private bool meshUpdated = false; + + /// + /// 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; } + } + + /// + /// True if the user has requested that spatial mapping start. + /// + private bool spatialMappingRequested = false; + + /// + /// 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; + + /// + /// True if the real-world texture has been updated. + /// + private bool updatedTexture = false; + + /// + /// Thread that retrieves the size of the submeshes. + /// + private Thread scanningThread; + + /// + /// Thread that filters the mesh once scanning has finished. + /// + private Thread filterThread; + /// + /// Mutex for threaded spatial mapping. + /// + private object lockScanning = new object(); + + /// + /// 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 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; + + /// + /// Public accessor for texturingRunning, which is whether the thread that updates the real-world texture is running. + /// + public bool IsTexturingRunning + { + get + { + return texturingRunning; + } + } + /// + /// If true, the script will add MeshColliders to all scanned chunks to allow physics collisions. + /// + private bool hasColliders = true; + + /// + /// 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; + + /// + /// 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; + + /// + /// 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 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 spatialMappingHelper.chunks; } + } + /// + /// 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, ZEDManager zedManager) + { + //Instantiate the low-level mesh processing helper. + spatialMappingHelper = new ZEDSpatialMappingHelper(zedManager.zedCamera, Resources.Load("Materials/SpatialMapping/Mat_ZED_Texture") as Material, Resources.Load("Materials/SpatialMapping/Mat_ZED_Geometry_Wireframe") as Material); + + //Assign basic values. + this.zedCamera = zedManager.zedCamera; + this.zedManager = zedManager; + scanningInitState = sl.ERROR_CODE.FAILURE; + + + } + + /// + /// 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) + { + //Create the Holder object, to which all scanned chunks will be parented. + holder = new GameObject(); + holder.name = "[ZED Mesh Holder (" + zedManager.name + ")]"; + holder.transform.position = Vector3.zero; + holder.transform.rotation = Quaternion.identity; + StaticBatchingUtility.Combine(holder); + + holder.transform.position = Vector3.zero; + holder.transform.rotation = Quaternion.identity; + spatialMappingRequested = true; + if (spatialMappingRequested && scanningInitState != sl.ERROR_CODE.SUCCESS) + { + scanningInitState = EnableSpatialMapping(resolutionPreset, rangePreset, isTextured); + } + + zedManager.gravityRotation = Quaternion.identity; + + pause = false; //Make sure the scanning doesn't start paused because it was left paused at the last scan. + + } + + /// + /// 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. + /// + /// 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; + + //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); + if (meshRenderer[0]) meshRenderer[0].isTextured = isTextured; + if (meshRenderer[1]) meshRenderer[1].isTextured = isTextured; + stopWanted = false; + running = true; + + 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 previous meshes. + ClearMeshes(); + + //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 from the ZED SDK. + scanningThread = new Thread(UpdateMesh); + updateThreadRunning = true; + if (OnMeshStarted != null) + { + OnMeshStarted(); //Invoke the event for other scripts, like ZEDMeshRenderer. + } + scanningThread.Start(); + } + return error; + } + + /// + /// Attach a new ZEDMeshRenderer to the ZED rig cameras. This is necessary to see the mesh. + /// + public void SetMeshRenderer() + { + if (!setMeshRenderer) //Make sure we haven't do this yet. + { + if (zedManager != null) + { + 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(); + if (!meshRenderer[0]) + { + meshRenderer[0] = left.gameObject.AddComponent(); + } + meshRenderer[0].Create(); + } + 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(); + if (!meshRenderer[1]) + { + meshRenderer[1] = right.gameObject.AddComponent(); + } + + meshRenderer[1].Create(); + } + setMeshRenderer = true; + } + } + } + + /// + /// Updates the current mesh, if scanning, and manages the start and stop states. + /// + public void Update() + { + SetMeshRenderer(); //Make sure we have ZEDMeshRenderers on the cameras, so we can see the mesh. + + if (meshUpdated || remainMeshes) + { + UpdateMeshMainthread(); + meshUpdated = false; + } + + if (stopWanted && !remainMeshes) + { + stopRunning = true; + stopWanted = false; + Stop(); + + } + + //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; + UpdateMeshMainthread(false); + + Thread disabling = new Thread(DisableSpatialMapping); + disabling.Start(); + if (hasColliders) + { + if (!zedManager.IsStereoRig && gravityEstimation != Vector3.zero && zedManager.transform.parent != null) + { + Quaternion rotationToApplyForGravity = Quaternion.Inverse(Quaternion.FromToRotation(Vector3.up, -gravityEstimation.normalized)); + holder.transform.localRotation = rotationToApplyForGravity; + + zedManager.gravityRotation = rotationToApplyForGravity; + } + + UpdateMeshCollider(); + } + else + { + running = false; + } + stopRunning = false; + } + } + + + /// + /// Gets the mesh data from the ZED SDK and stores it for later update in the Unity mesh. + /// + private void UpdateMesh() + { + while (updateThreadRunning) + { + if (!remainMeshes) //If we don't have leftover meshes to apply from the last update. + { + lock (lockScanning) + { + if (meshUpdated == false && updateTexture) //If we need to update the texture, prioritize that. + { + //Get the last size of the mesh and get the texture size. + spatialMappingHelper.ApplyTexture(); + meshUpdated = true; + updateTexture = false; + updatedTexture = true; + updateThreadRunning = false; + } + else if (zedCamera.GetMeshRequestStatus() == sl.ERROR_CODE.SUCCESS && !pause && meshUpdated == false) + { + 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. + Thread.Sleep(5); + } + else //If there are meshes that were collected but not processed yet. Happens if the last update took too long to process. + { + //Check every 5ms if the meshes are done being processed. + Thread.Sleep(5); + } + + } + } + + /// + /// Destroys all submeshes. + /// + private void ClearMeshes() + { + if (holder != null) + { + foreach (Transform child in holder.transform) + { + GameObject.Destroy(child.gameObject); + } + spatialMappingHelper.Clear(); + } + } + + /// + /// 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; + } + + + /// + /// 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) + { + //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) //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. + int verticesOffset = 0, trianglesOffset = 0, uvsOffset = 0; + if (remainMeshes && spreadUpdateOverTime) + { + verticesOffset = verticesOffsetLastFrame; + trianglesOffset = trianglesOffsetLastFrame; + uvsOffset = uvsOffsetLastFrame; + indexUpdate = indexLastFrame; + } + + //Clear all existing meshes and process the last ones. + if (updatedTexture) + { + ClearMeshes(); + spatialMappingHelper.SetMeshAndTexture(); + if (meshRenderer[0]) meshRenderer[0].isTextured = isTextured; + if (meshRenderer[1]) meshRenderer[1].isTextured = isTextured; + + } + + //Process the last meshes. + for (; indexUpdate < spatialMappingHelper.NumberUpdatedSubMesh; indexUpdate++) + { + + 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; //It has. Set this flag so we know to pick up where we left off next frame. + break; + } + } + if (spreadUpdateOverTime) + { + indexLastFrame = indexUpdate; + } + else + { + indexLastFrame = 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; + uvsOffsetLastFrame = 0; + indexLastFrame = 0; + remainMeshes = false; + meshUpdated = false; + zedCamera.RequestMesh(); + } + //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; + + verticesOffsetLastFrame = verticesOffset; + trianglesOffsetLastFrame = trianglesOffset; + uvsOffsetLastFrame = uvsOffset; + } + + //Save the mesh here if we requested it to be saved, as we just updated the meshes, including textures, if applicable. + if (saveRequested && remainMeshes == false) + { + if (!isTextured || updatedTexture) + { + SaveMeshNow(savePath); + saveRequested = false; + } + } + } + + + if (OnMeshUpdate != null) + { + OnMeshUpdate(); //Call the event if it has at least one listener. + } + + //The texture update is done in one pass, so this is only called once after the mesh has stopped scanning. + if (updatedTexture) + { + DisableSpatialMapping(); + updatedTexture = false; + running = false; + texturingRunning = false; + if (hasColliders) + { + UpdateMeshCollider(); + } + else + { + running = false; + } + } + } + + + public void ClearAllMeshes() + { + + GameObject[] gos = GameObject.FindObjectsOfType() as GameObject[]; + + spatialMappingHelper.Clear(); + for (int i = 0; i < gos.Length; i++) + { + string targetName = "[ZED Mesh Holder (" + zedManager.name + ")]"; + if (gos[i] != null && gos[i].name.Contains(targetName)) + { + GameObject.Destroy(gos[i]); + } + } + } + + /// + /// 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) + { + display = newDisplayState; + } + + /// + /// 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) + { + pause = newPauseState; + zedCamera.PauseSpatialMapping(newPauseState); + } + + /// + /// 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) + { + ChunkList.Clear(); + foreach (var submesh in Chunks) + { + ChunkList.Add(submesh.Value); + } + lock (lockScanning) + { + spatialMappingHelper.UpdateMeshCollider(ChunkList); + } + if (OnMeshReady != null) + { + OnMeshReady(); + } + 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) + { + updateThreadRunning = false; + scanningThread.Join(); + } + ClearMeshes(); + GameObject.Destroy(holder); + DisableSpatialMapping(); + } + + /// + /// 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; + spatialMappingHelper.DisableSpatialMapping(); + scanningInitState = sl.ERROR_CODE.FAILURE; + spatialMappingRequested = false; + + } + } + + /// + /// Save the mesh as an .obj file, and the area database as an .area file. + /// This can be quite time-comsuming if you mapped a large area. + /// + public void RequestSaveMesh(string meshFilePath = "Assets/ZEDMesh.obj") + { + saveRequested = true; + savePath = meshFilePath; + + if (updateThreadRunning) + { + StopStatialMapping(); //Stop the mapping if it hasn't stopped already. + } + + } + + /// + /// 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") + { + if (holder == null) + { + holder = new GameObject(); + holder.name = "[ZED Mesh Holder (" + zedManager.name + ")]"; + holder.transform.position = Vector3.zero; + holder.transform.rotation = Quaternion.identity; + StaticBatchingUtility.Combine(holder); + } + + + if (OnMeshStarted != null) + { + OnMeshStarted(); + } + //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)); + } + + zedCamera.DisableTracking(); + Quaternion quat = Quaternion.identity; Vector3 tr = Vector3.zero; + if (zedCamera.EnableTracking(ref quat, ref tr, true, false, false, System.IO.File.Exists(basePath + ".area") ? basePath + ".area" : "") != sl.ERROR_CODE.SUCCESS) + { + Debug.LogWarning(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.TRACKING_NOT_INITIALIZED)); + } + + updateTexture = false; + updatedTexture = false; + bool meshUpdatedLoad = false; + lock (lockScanning) + { + ClearMeshes(); + meshUpdatedLoad = spatialMappingHelper.LoadMesh(meshFilePath); + + if (meshUpdatedLoad) + { + //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. + if (!updateTexture) + { + spatialMappingHelper.RetrieveMesh(); + } + } + } + + if (meshUpdatedLoad) + { + //Update the buffer on Unity's side. + UpdateMeshMainthread(false); + + //Add colliders and scan for gravity. + if (hasColliders) + { + if (!zedManager.IsStereoRig && gravityEstimation != Vector3.zero) + { + Quaternion rotationToApplyForGravity = Quaternion.Inverse(Quaternion.FromToRotation(Vector3.up, -gravityEstimation.normalized)); + holder.transform.rotation = rotationToApplyForGravity; + zedManager.gravityRotation = rotationToApplyForGravity; + } + UpdateMeshCollider(); + foreach (Chunk c in ChunkList) + { + c.o.transform.localRotation = Quaternion.identity; + } + + } + + if (OnMeshReady != null) + { + OnMeshReady(); //Call the event if it has at least one listener. + } + + return true; + } + return false; + } + + /// + /// 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) //Wait for the thread to be available. + { + 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; + if (filter) + { + FilterMesh(); + } + MergeChunks(); + } + + /// + /// Consolidates meshes to get fewer chunks - one for every MAX_SUBMESH vertices. Then applies to + /// actual meshes in Unity. + /// + public void MergeChunks() + { + lock (lockScanning) + { + 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(); + } + + + /// + /// Stops the spatial mapping and begins the final processing, including adding texture. + /// + public bool ApplyTexture() + { + updateTexture = true; + if (updateThreadRunning) + { + updateThreadRunning = false; + scanningThread.Join(); + } + scanningThread = new Thread(ApplyTextureThreaded); + updateThreadRunning = true; + scanningThread.Start(); + texturingRunning = true; + return true; + } + + /// + /// Stop the spatial mapping and calls appropriate functions to process the final mesh. + /// + private void Stop() + { + gravityEstimation = zedCamera.GetGravityEstimate(); + + if (isTextured) + { + ApplyTexture(); + } + else + { + stopRunning = false; + if (updateThreadRunning) + { + updateThreadRunning = false; + scanningThread.Join(); + } + + ClearMeshes(); + PostProcessMesh(true); + //filterThread = new Thread(() => PostProcessMesh(true)); + //filterThread.Start(); + stopRunning = true; + } + + SwitchDisplayMeshState(true); //Make it default to visible. + } + + /// + /// Returns true from the moment a scan has started until the post-process is finished. + /// + /// + public bool IsRunning() + { + return running; + } + + /// + /// 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; + } + + /// + /// Combines the meshes from all the current chunks and saves them into a single mesh. If textured, + /// will also save a .mtl file and .png file. + /// This must only be called once all the chunks are completely finalized, or else they won't be filtered + /// or have their UVs set. + /// Called after RequestSaveMesh has been called after the main thread has the chance to stop the scan + /// and finalize everything. + /// + /// Where the mesh, material, and texture files will be saved. + private void SaveMeshNow(string meshFilePath = "Assets/ZEDMesh.obj") + { + + //Make sure the destination file ends in .obj - only .obj file format is supported. + string extension = meshFilePath.Substring(meshFilePath.Length - 4); + if (extension.ToLower() != ".obj") + { + Debug.LogError("Couldn't save to " + meshFilePath + ": Must save as .obj."); + } + + lock (lockScanning) + { + Debug.Log("Saving mesh to " + meshFilePath); + //Count how many vertices and triangles are in all the chunk meshes so we know how large of an array to allocate. + int vertcount = 0; + int tricount = 0; + + foreach (Chunk chunk in Chunks.Values) + { + vertcount += chunk.mesh.vertices.Length; + tricount += chunk.mesh.triangles.Length; + } + if (vertcount == 0) return; + + Vector3[] vertices = new Vector3[vertcount]; + Vector2[] uvs = new Vector2[vertcount]; + Vector3[] normals = new Vector3[vertcount]; + int[] triangles = new int[tricount]; + + int vertssofar = 0; //We keep an ongoing tally of how many verts/tris we've put so far so as to increment + int trissofar = 0; //where we copy to in the arrays, and also to increment the vertex indices in the triangle array. + + for (int i = 0; i < Chunks.Keys.Count; i++) + { + Mesh chunkmesh = Chunks[i].mesh; //Shorthand. + + Array.Copy(chunkmesh.vertices, 0, vertices, vertssofar, chunkmesh.vertices.Length); + Array.Copy(chunkmesh.uv, 0, uvs, vertssofar, chunkmesh.uv.Length); + + chunkmesh.RecalculateNormals(); + Array.Copy(chunkmesh.normals, 0, normals, vertssofar, chunkmesh.normals.Length); + + Array.Copy(chunkmesh.triangles, 0, triangles, trissofar, chunkmesh.triangles.Length); + for (int t = trissofar; t < trissofar + chunkmesh.triangles.Length; t++) + { + triangles[t] += vertssofar; + } + + vertssofar += chunkmesh.vertices.Length; + trissofar += chunkmesh.triangles.Length; + } + + Material savemat = Chunks[0].o.GetComponent().material; //All chunks share the same material. + + //We'll need to know the base file name for this and the .mtl file. We'll extract it. + //Since both forward and backslashes are valid for the file pack, determine which they used last. + int forwardindex = meshFilePath.LastIndexOf('/'); + int backindex = meshFilePath.LastIndexOf('\\'); + int slashindex = forwardindex > backindex ? forwardindex : backindex; + string basefilename = meshFilePath.Substring(slashindex + 1, meshFilePath.LastIndexOf(".") - slashindex - 1); + + //Create the string file. + //Importantly, we flip the X value (and reverse the triangles) since the scanning module uses a different handedness than Unity. + StringBuilder objstring = new StringBuilder(); + + objstring.Append("mtllib " + basefilename + "\n"); + + objstring.Append("g ").Append("ZEDScan").Append("\n"); + foreach (Vector3 vec in vertices) + { + //X is flipped because of Unity's handedness. + objstring.Append(string.Format("v {0} {1} {2}\n", -vec.x, vec.y, vec.z)); + } + objstring.Append("\n"); + foreach (Vector2 uv in uvs) + { + objstring.Append(string.Format("vt {0} {1}\n", uv.x, uv.y)); + } + objstring.Append("\n"); + foreach (Vector3 norm in normals) + { + objstring.Append(string.Format("vn {0} {1} {2}\n", -norm.x, norm.y, norm.z)); + } + objstring.Append("\n"); + + if (isTextured) + { + objstring.Append("usemtl ").Append(basefilename).Append("\n"); + objstring.Append("usemap ").Append(basefilename).Append("\n"); + } + + for (int i = 0; i < triangles.Length; i += 3) + { + //Triangles are reversed so that surface normals face the right way after the X vertex flip. + objstring.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", + triangles[i + 2] + 1, triangles[i + 1] + 1, triangles[i + 0] + 1)); + } + + + System.IO.StreamWriter swriter = new System.IO.StreamWriter(meshFilePath); + swriter.Write(objstring.ToString()); + swriter.Close(); + + //Create a texture and .mtl file for your scan, if textured. + if (isTextured) + { + //First, the texture. + //You can't save a Texture2D directly to a file since it's stored on the GPU. + //So we use a RenderTexture as a buffer, which we can read into a new Texture2D on the CPU-side. + Texture textosave = savemat.mainTexture; + + RenderTexture buffertex = new RenderTexture(textosave.width, textosave.height, 0); + Graphics.Blit(textosave, buffertex); + + RenderTexture oldactivert = RenderTexture.active; + RenderTexture.active = buffertex; + + Texture2D texcopy = new Texture2D(textosave.width, textosave.height); + texcopy.ReadPixels(new Rect(0, 0, buffertex.width, buffertex.height), 0, 0); + texcopy.Apply(); //It's now on the CPU! + + byte[] imagebytes = texcopy.EncodeToPNG(); + string imagepath = meshFilePath.Substring(0, meshFilePath.LastIndexOf(".")) + ".png"; + System.IO.File.WriteAllBytes(imagepath, imagebytes); + + RenderTexture.active = oldactivert; + + //Now the material file. + StringBuilder mtlstring = new StringBuilder(); + + mtlstring.Append("newmtl " + basefilename + "\n"); + + mtlstring.Append("Ka 1.000000 1.000000 1.000000\n"); + mtlstring.Append("Kd 1.000000 1.000000 1.000000\n"); + mtlstring.Append("Ks 0.000000 0.000000 0.000000\n"); + mtlstring.Append("Tr 1.000000\n"); + mtlstring.Append("illum 1\n"); + mtlstring.Append("Ns 1.000000\n"); + mtlstring.Append("map_Kd " + basefilename + ".png"); + + string mtlpath = meshFilePath.Substring(0, meshFilePath.LastIndexOf(".")) + ".mtl"; + swriter = new System.IO.StreamWriter(mtlpath); + swriter.Write(mtlstring.ToString()); + swriter.Close(); + } + } + + //Save the .area file for spatial memory. + string areaName = meshFilePath.Substring(0, meshFilePath.LastIndexOf(".")) + ".area"; + zedCamera.SaveCurrentArea(areaName); + } + + /// + /// 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() && spatialMappingHelper != null && spatialMappingHelper.chunks.Count != 0 && display) + { + foreach (var submesh in spatialMappingHelper.chunks) + { + if (submesh.Value.proceduralMesh.mesh != null) + { + Gizmos.DrawWireMesh(submesh.Value.proceduralMesh.mesh.sharedMesh, submesh.Value.o.transform.position, submesh.Value.o.transform.rotation); + } + } + } + } +#endif + + + /// + /// 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; + /// + /// Maximum number of chunks. It's best to get relatively few chunks and to update them quickly. + /// + private const int MAX_SUBMESH = 1000; + + /*** 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; + + /// + /// Public accessor for the number of chunks that have been updated. + /// + public int NumberUpdatedSubMesh + { + get { return numUpdatedSubmesh; } + } + + /// + /// Gets the material used to draw spatial mapping meshes without real-world textures. + /// + /// + public Material GetMaterialSpatialMapping() + { + return materialMesh; + } + + /// + /// Constructor. Gets the ZEDCamera instance and sets materials used on the meshes. + /// + /// + /// + public ZEDSpatialMappingHelper(sl.ZEDCamera camera, Material materialTexture, Material materialMesh) + { + zedCamera = camera; + this.materialTexture = materialTexture; + this.materialMesh = materialMesh; + } + + /// + /// Updates the range to match the specified preset. + /// + static public float ConvertRangePreset(RANGE rangePreset) + { + + if (rangePreset == RANGE.NEAR) + { + return 3.5f; + } + else if (rangePreset == RANGE.MEDIUM) + { + return 5.0f; + } + if (rangePreset == RANGE.FAR) + { + return 10.0f; + } + return 5.0f; + } + + /// + /// Updates the resolution to match the specified preset. + /// + static public float ConvertResolutionPreset(RESOLUTION resolutionPreset) + { + if (resolutionPreset == RESOLUTION.HIGH) + { + return 0.05f; + } + else if (resolutionPreset == RESOLUTION.MEDIUM) + { + return 0.10f; + } + if (resolutionPreset == RESOLUTION.LOW) + { + return 0.15f; + } + return 0.10f; + } + + /// + /// Tells the ZED SDK to begin spatial mapping. + /// + /// + + public sl.ERROR_CODE EnableSpatialMapping(float resolutionMeter, float maxRangeMeter, bool saveTexture) + { + return zedCamera.EnableSpatialMapping(resolutionMeter, maxRangeMeter, saveTexture); + } + + /// + /// Tells the ZED SDK to stop spatial mapping. + /// + public void DisableSpatialMapping() + { + zedCamera.DisableSpatialMapping(); + } + + /// + /// Create a new submesh to contain the data retrieved from the ZED. + /// + public ZEDSpatialMapping.Chunk CreateNewMesh(int i, Material meshMat, Transform holder) + { + //Initialize the chunk and create a GameObject for it. + ZEDSpatialMapping.Chunk chunk = new ZEDSpatialMapping.Chunk(); + chunk.o = GameObject.CreatePrimitive(PrimitiveType.Quad); + chunk.o.layer = zedCamera.TagOneObject; + chunk.o.GetComponent().sharedMesh = null; + chunk.o.name = "Chunk" + chunks.Count; + chunk.o.transform.localPosition = Vector3.zero; + chunk.o.transform.localRotation = Quaternion.identity; + + Mesh m = new Mesh(); + m.MarkDynamic(); //Allows it to be updated regularly without performance issues. + chunk.mesh = m; + + //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; + meshRenderer.receiveShadows = false; + meshRenderer.enabled = true; + meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; + meshRenderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; + + //Sets the position and parent of the chunk. + chunk.o.transform.parent = holder; + chunk.o.layer = zedCamera.TagOneObject; + + //Add the chunk to the dictionary. + chunk.proceduralMesh.mesh = chunk.o.GetComponent(); + chunks.Add(i, chunk); + return chunk; + } + + /// + /// 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(); //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]; + MeshCollider m = submesh.o.GetComponent(); + + if (m == null) + { + m = submesh.o.AddComponent(); + } + + //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) + { + idsToDestroy.Add(i); + continue; + } + + m.sharedMesh = tempMesh; + + m.sharedMesh.RecalculateNormals(); + m.sharedMesh.RecalculateBounds(); + } + + //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 the buffer data now that we have Unity meshes. + } + + /// + /// Tells the ZED SDK to calculate the size of the texture and the UVs. + /// + public void ApplyTexture() + { + zedCamera.ApplyTexture(numVerticesInSubmesh, numTrianglesInSubmesh, ref numUpdatedSubmesh, UpdatedIndices, ref numVertices, ref numTriangles, texturesSize, MAX_SUBMESH); + } + + /// + /// Tells the ZED SDK to update its internal mesh from spatial mapping. The resulting mesh will later be retrieved with RetrieveMesh(). + /// + public void UpdateMesh() + { + zedCamera.UpdateMesh(numVerticesInSubmesh, numTrianglesInSubmesh, ref numUpdatedSubmesh, UpdatedIndices, ref numVertices, ref numTriangles, MAX_SUBMESH); + ResizeMesh(); + } + + /// + /// 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 the current buffer data. + /// + public void Clear() + { + chunks.Clear(); + + vertices = new Vector3[0]; + triangles = new int[0]; + uvs = new Vector2[0]; + + System.Array.Clear(vertices, 0, vertices.Length); + System.Array.Clear(triangles, 0, triangles.Length); + } + + /// + /// Process data from a submesh retrieved from the ZED SDK into a chunk, which includes a GameObject and visible mesh. + /// + /// 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)) //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; + //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]]; + } + if (dynamicMesh.vertices == null || dynamicMesh.vertices.Length != numVerticesInSubmesh[indexUpdate]) + { + dynamicMesh.vertices = new Vector3[numVerticesInSubmesh[indexUpdate]]; + } + + //Clear the old mesh data. + currentMesh.Clear(); + + //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. + trianglesOffset += 3 * numTrianglesInSubmesh[indexUpdate]; + currentMesh.vertices = dynamicMesh.vertices; + currentMesh.SetTriangles(dynamicMesh.triangles, 0, false); + + dynamicMesh.mesh.sharedMesh = currentMesh; + + //If textured, add UVs. + if (updatedTex) + { + Vector2[] localUvs = new Vector2[numVerticesInSubmesh[indexUpdate]]; + subMesh.o.GetComponent().sharedMaterial = materialTexture; + System.Array.Copy(uvs, uvsOffset, localUvs, 0, numVerticesInSubmesh[indexUpdate]); + uvsOffset += numVerticesInSubmesh[indexUpdate]; + currentMesh.uv = localUvs; + + } + } + + /// + /// 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, 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); + + vertices = new Vector3[numVertices]; + uvs = new Vector2[numVertices]; + triangles = new int[3 * numTriangles]; + + zedCamera.RetrieveMesh(vertices, triangles, MAX_SUBMESH, uvs, texture); + } + } + + /// + /// Loads a mesh from a file path and allocates the buffers accordingly. + /// + /// Path to the mesh file. + /// + public bool LoadMesh(string meshFilePath) + { + bool r = zedCamera.LoadMesh(meshFilePath, numVerticesInSubmesh, numTrianglesInSubmesh, ref numUpdatedSubmesh, UpdatedIndices, ref numVertices, ref numTriangles, MAX_SUBMESH, texturesSize); + vertices = new Vector3[numVertices]; + uvs = new Vector2[numVertices]; + triangles = new int[3 * numTriangles]; + return r; + } + + /// + /// 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]; + } + + public int GetHeightTexture() + { + return texturesSize[1]; + } + + /// + /// 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]; //Allocation is faster than resizing. + } + + if (triangles.Length < 3 * numTriangles) + { + triangles = new int[3 * numTriangles * 2]; + } + } + + /// + /// 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); + } + + /// + /// 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() + { + zedCamera.MergeChunks(MAX_SUBMESH, numVerticesInSubmesh, numTrianglesInSubmesh, ref numUpdatedSubmesh, UpdatedIndices, ref numVertices, ref numTriangles, MAX_SUBMESH); + } + + } +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs.meta new file mode 100644 index 0000000..6330e95 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/SpatialMapping/ZEDSpatialMapping.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5c2ff2779e6f06a4aa8c58db879d241a +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities.meta new file mode 100644 index 0000000..281a6c5 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 726403919205af2449e5bb7711b412b3 +folderAsset: yes +timeCreated: 1507318608 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/CappedStack.cs b/Assets/ZED/SDK/Helpers/Scripts/Utilities/CappedStack.cs new file mode 100644 index 0000000..8ca405c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/CappedStack.cs @@ -0,0 +1,40 @@ +using System.Collections; +using System.Collections.Generic; + +/// +/// Extended version of List used to give stack functionality, but with a maximum capacity. +/// +public class CappedStack : List +{ + public int maxValues; + + public CappedStack(int max) + { + maxValues = max; + } + + /// + /// Adds the object to the top of the stack. If stack is longer than maxValues, + /// removes the oldest item. + /// + /// Object to go on top of the stack. + public void Push(T val) + { + Add(val); + if (Count > maxValues) + { + RemoveAt(0); + } + } + + /// + /// Returns the item on top of the stack and removes it. + /// + /// Top stack item. + public T Pop() + { + T val = this[Count - 1]; + RemoveAt(Count - 1); + return val; + } +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/CappedStack.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities/CappedStack.cs.meta new file mode 100644 index 0000000..df925f3 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/CappedStack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef80e042d0e20c643a2f25cb7d2f2003 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs b/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs new file mode 100644 index 0000000..69742ad --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs @@ -0,0 +1,398 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; +using UnityEngine.VR; + +/// +/// 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 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 ("Loading...", "Camera is not detected", etc.) + /// + private UnityEngine.UI.Text textleft; + + /// + /// Text under the loading sign for stereo rig's right eye ("Loading...", "Camera is not detected", etc.) + /// + private UnityEngine.UI.Text textright; + + /// + /// 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 the mono rig. Contains the text, background, and loading graphic. + /// + private GameObject warningmono; + + /// + /// Warning container for the stereo rig's left eye. Contains the text, background, and loading graphic. + /// + private GameObject warningleft; + + /// + /// Warning container for the stereo rig's right eye. Contains the text, background, and loading graphic. + /// + private GameObject warningright; + + /// + /// 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; + + /// + /// 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 used to delay clearing the text by 0.2 seconds once the camera is initialized. + /// + private float timer; + + /// + /// Reference to the loading spinner animation for the mono rig. + /// + private GameObject imagemono; + + /// + /// Reference to the loading spinner animation for the stereo rig's left eye. + /// + private GameObject imageleft; + + /// + /// Reference to the loading spinner animation for the stereo rig's right eye. + /// + private GameObject imageright; + + /// + /// 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; + + /// + /// The zed manager. + /// + private ZEDManager zedManager; + + /// + /// 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() + { + zedManager = GetComponent(); + 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); + warningmono.GetComponent().renderMode = RenderMode.ScreenSpaceCamera; + + //Set the target camera to whichever mono camera in the rig has the highest depth. + Camera highestdepthzedcam = zedManager.GetLeftCamera(); + if (zedManager.GetRightCamera() != null && (highestdepthzedcam == null || zedManager.GetRightCamera().depth > highestdepthzedcam.depth)) + { + highestdepthzedcam = zedManager.GetRightCamera(); + } + + warningmono.GetComponent().worldCamera = highestdepthzedcam; + + textmono = warningmono.GetComponentInChildren(); + textmono.color = Color.white; + + if (!sl.ZEDCamera.CheckPlugin()) + { + textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SDK_NOT_INSTALLED); + } + imagemono = warningmono.transform.GetChild(0).GetChild(1).gameObject; + imagemono.transform.parent.gameObject.SetActive(true); + ready = false; + } + else //In VR, we use two Screen Space - Camera canvases, one for each eye. + { + //Instantiate the left warning prefab and set basic settings for it. + warningleft = Instantiate(Resources.Load("PrefabsUI/Warning_VR") as GameObject, zedManager.GetLeftCameraTransform()); + warningleft.SetActive(true); + warningleft.GetComponent().worldCamera = zedManager.GetLeftCamera(); + warningleft.GetComponent().planeDistance = 1; + textleft = warningleft.GetComponentInChildren(); + textleft.color = Color.white; + imageleft = warningleft.transform.GetChild(0).GetChild(1).gameObject; + imageleft.transform.parent.gameObject.SetActive(true); + + //Instantiate the right warning prefab and set basic settings for it. + warningright = Instantiate(Resources.Load("PrefabsUI/Warning_VR") as GameObject, zedManager.GetRightCameraTransform()); + warningright.SetActive(true); + warningright.GetComponent().worldCamera = zedManager.GetRightCamera(); + warningright.GetComponent().planeDistance = 1; + textright = warningright.GetComponentInChildren(); + textright.color = Color.white; + imageright = warningright.transform.GetChild(0).GetChild(1).gameObject; + imageright.transform.parent.gameObject.SetActive(true); + + 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); + } + + ready = false; + } + } + + /// + /// 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; + zedManager.OnZEDDisconnected -= ZEDDisconnected; + } + + /// + /// 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) //Using the mono rig. + { + warningmono.SetActive(true); + imagemono.SetActive(true); + + warningmono.transform.GetChild(0).gameObject.SetActive(true); + textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.ZED_IS_DISCONNECETD); + warningmono.layer = 30; + + ready = false; + } + + if (warningleft) //Using the stereo rig. + { + warningleft.SetActive(true); + imageleft.SetActive(true); + warningleft.transform.GetChild(0).gameObject.SetActive(true); + textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.ZED_IS_DISCONNECETD); + warningleft.layer = 30; + + warningright.SetActive(true); + imageright.SetActive(true); + warningright.transform.GetChild(0).gameObject.SetActive(true); + textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.ZED_IS_DISCONNECETD); + warningright.layer = 30; + + ready = false; + } + } + + /// + /// If visible, print the loading status of the ZED, including relevant errors. + /// + void Update() + { + 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) //Last initialization attempt was successful. + { + if (!ready) + { + + if (textmono) + { + textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SDK_MODULE_LOADING); + } + else if (textleft) + { + textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SDK_MODULE_LOADING); + textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SDK_MODULE_LOADING); + } + + + } + else + { + timer += Time.deltaTime; //Clear text after a short delay. + if (timer > 0.2f) + { + if (textmono) + { + textmono.text = ""; + } + else if (textleft) + { + textleft.text = ""; + textright.text = ""; + } + + } + + if (imagemono) + { //Disable mono rig canvas. + imagemono.gameObject.SetActive(false); + } + else if (imageleft) + { //Disable stereo rig canvases. + imageleft.gameObject.SetActive(false); + imageright.gameObject.SetActive(false); + } + } + } + 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); + } + else if (textleft) + { + textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_LOADING); + textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_LOADING); + } + + } + else if (e == sl.ERROR_CODE.CAMERA_NOT_DETECTED && oldInitStatus == sl.ERROR_CODE.CAMERA_NOT_DETECTED) //"Camera not detected" + { + if (textmono) + { + textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.UNABLE_TO_OPEN_CAMERA); + } + else if (textleft) + { + textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.UNABLE_TO_OPEN_CAMERA); + 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) //"Unable to open camera" + { + if (textmono) + { + textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_DETECTION_ISSUE); + } + else if (textleft) + { + textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_DETECTION_ISSUE); + 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) //"Camera motion sensor not detected" + { + if (textmono) + { + textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SENSOR_NOT_DETECTED); + } + else if (textleft) + { + textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SENSOR_NOT_DETECTED); + 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)//"Low USB bandwidth" + { + if (textmono) + { + textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.LOW_USB_BANDWIDTH); + } + else if (textleft) + { + textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.LOW_USB_BANDWIDTH); + 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) + { + textmono.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_NOT_INITIALIZED); + } + else if (textleft) + { + textleft.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_NOT_INITIALIZED); + textright.text = ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.CAMERA_NOT_INITIALIZED); + } + } + oldInitStatus = e; + } + + if (ready) //ZED has finished initializing. Set a timer, then disable texts after it expires. + { + timerWarning += Time.deltaTime; + if (timerWarning > 0.5f) + { + if (warningmono) + { + warningmono.SetActive(false); + } + else if (warningleft) + { + warningleft.SetActive(false); + warningright.SetActive(false); + } + } + + init = true; //Prevents logic above the if (ready) check from running each frame. + + if (imagemono) + { + imagemono.gameObject.transform.parent.gameObject.SetActive(false); + } + else if (imageleft) + { + imageleft.gameObject.transform.parent.gameObject.SetActive(false); + imageright.gameObject.transform.parent.gameObject.SetActive(false); + } + } + + } + + /// + /// 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/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs.meta new file mode 100644 index 0000000..718b02d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/GUIMessage.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7c602d2dc840f0144911c39c566846cb +timeCreated: 1507318830 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/LayerHandler.cs b/Assets/ZED/SDK/Helpers/Scripts/Utilities/LayerHandler.cs new file mode 100644 index 0000000..494cc24 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/LayerHandler.cs @@ -0,0 +1,153 @@ +using UnityEngine; +#if UNITY_EDITOR + using UnityEditor; +#endif + + +public class LayerHandler +{ + + public static bool[] layer_pack_used = new bool[4]; + private LayerHandler() + { + for (int k = 0; k < 4; k++) + layer_pack_used [k] = false; + } + + private static LayerHandler _instance = null; + + public static LayerHandler GetInstance() + { + if (_instance == null) + { + _instance = new LayerHandler(); + } + return _instance; + } + + + public enum LAYER_MODE + { + LAYER_MODE_LEFT_SCREEN, + LAYER_MODE_RIGHT_SCREEN, + LAYER_MODE_LEFT_FINALSCREEN, + LAYER_MODE_RIGHT_FINALSCREEN + }; + + public enum LAYER_PACK_LAYER_NUMBER + { + LAYER_PACK_CAM1_LS = 27, + LAYER_PACK_CAM1_RS = 28, + LAYER_PACK_CAM1_LFS = 29, + LAYER_PACK_CAM1_RFS = 30, + + LAYER_PACK_CAM2_LS = 23, + LAYER_PACK_CAM2_RS = 24, + LAYER_PACK_CAM2_LFS = 25, + LAYER_PACK_CAM2_RFS = 26, + + LAYER_PACK_CAM3_LS = 19, + LAYER_PACK_CAM3_RS = 20, + LAYER_PACK_CAM3_LFS = 21, + LAYER_PACK_CAM3_RFS = 22, + + LAYER_PACK_CAM4_LS = 15, + LAYER_PACK_CAM4_RS = 16, + LAYER_PACK_CAM4_LFS = 17, + LAYER_PACK_CAM4_RFS = 18 + }; + + + public void setUsed(sl.ZED_CAMERA_ID lp, bool used) + { + layer_pack_used [(int)lp] = used; + } + + public bool getUsed(sl.ZED_CAMERA_ID lp) + { + return layer_pack_used [(int)lp]; + } + + + public int getLayerNumber(sl.ZED_CAMERA_ID lp, LAYER_MODE mode) + { + switch (lp) { + case sl.ZED_CAMERA_ID.CAMERA_ID_01: + { + switch (mode) { + case LAYER_MODE.LAYER_MODE_LEFT_SCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM1_LS; + case LAYER_MODE.LAYER_MODE_RIGHT_SCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM1_RS; + case LAYER_MODE.LAYER_MODE_LEFT_FINALSCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM1_LFS; + case LAYER_MODE.LAYER_MODE_RIGHT_FINALSCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM1_RFS; + default : + return -1; + } + + } + break; + + case sl.ZED_CAMERA_ID.CAMERA_ID_02: + { + switch (mode) { + case LAYER_MODE.LAYER_MODE_LEFT_SCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM2_LS; + case LAYER_MODE.LAYER_MODE_RIGHT_SCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM2_RS; + case LAYER_MODE.LAYER_MODE_LEFT_FINALSCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM2_LFS; + case LAYER_MODE.LAYER_MODE_RIGHT_FINALSCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM2_RFS; + default : + return -1; + } + } + break; + + case sl.ZED_CAMERA_ID.CAMERA_ID_03: + { + switch (mode) { + case LAYER_MODE.LAYER_MODE_LEFT_SCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM3_LS; + case LAYER_MODE.LAYER_MODE_RIGHT_SCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM3_RS; + case LAYER_MODE.LAYER_MODE_LEFT_FINALSCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM3_LFS; + case LAYER_MODE.LAYER_MODE_RIGHT_FINALSCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM3_RFS; + default : + return -1; + } + } + break; + + case sl.ZED_CAMERA_ID.CAMERA_ID_04: + { + switch (mode) { + case LAYER_MODE.LAYER_MODE_LEFT_SCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM4_LS; + case LAYER_MODE.LAYER_MODE_RIGHT_SCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM4_RS; + case LAYER_MODE.LAYER_MODE_LEFT_FINALSCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM4_LFS; + case LAYER_MODE.LAYER_MODE_RIGHT_FINALSCREEN: + return (int)LAYER_PACK_LAYER_NUMBER.LAYER_PACK_CAM4_RFS; + default : + return -1; + } + } + break; + + default : + return -1; + } + } + + + + +} + \ No newline at end of file diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/LayerHandler.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities/LayerHandler.cs.meta new file mode 100644 index 0000000..39e47cb --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/LayerHandler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c3cb8b0528078b140a84a096f2f1fcf4 +timeCreated: 1543443417 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs b/Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs new file mode 100644 index 0000000..51ce8d3 --- /dev/null +++ b/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/Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs.meta new file mode 100644 index 0000000..516ed1d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/LoadingFade.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9dd9e324b3de69545a9eb8b1e787bd8f +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs b/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs new file mode 100644 index 0000000..1908ebf --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs @@ -0,0 +1,102 @@ +using UnityEngine; +#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; + this.optTooltip = tooltip; + } + +#if UNITY_EDITOR + /// + /// 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 ) + { + var propertyAttribute = this.attribute as LabelOverride; + label.text = propertyAttribute.label; + label.tooltip = propertyAttribute.optTooltip; + EditorGUI.PropertyField( position , property , label ); + } + } +#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; + } +} + +#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) + { + return EditorGUI.GetPropertyHeight(property, label, true); + } + + public override void OnGUI(Rect position, + SerializedProperty property, + GUIContent label) + { + GUI.enabled = false; + var propertyAttribute = this.attribute as ReadOnlyAttribute; + label.text = propertyAttribute.label; + EditorGUI.PropertyField(position, property, label, true); + GUI.enabled = true; + } + +} +#endif \ No newline at end of file diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs.meta new file mode 100644 index 0000000..d11fd37 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/Utils.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6c5cd0f14b161ec4bb8fd1a35edd8181 +timeCreated: 1511812224 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs new file mode 100644 index 0000000..176d96a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs @@ -0,0 +1,203 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + + +/// +/// 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 +{ + + /// + /// 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; + } + } + + /// + /// 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. + /// + SCREEN_RESOLUTION, + /// + /// The ZED tracking could not be initialized. + /// + TRACKING_NOT_INITIALIZED, + /// + /// The camera failed to initialize. + /// + CAMERA_NOT_INITIALIZED, + /// + /// The camera has not been initialized yet. + /// + CAMERA_LOADING, + /// + /// SDK module are loading (tracking, object detection...) + /// + SDK_MODULE_LOADING, + /// + /// Could not open the camera. + /// + UNABLE_TO_OPEN_CAMERA, + /// + /// Camera detection issue. + /// + CAMERA_DETECTION_ISSUE, + /// + /// Motion sensor not detected (ZED Mini only). + /// + SENSOR_NOT_DETECTED, + /// + /// Low USB bandwidth. + /// + LOW_USB_BANDWIDTH, + /// + /// SteamVR plugin Camera Rig prefab not found. + /// + VR_CAMERA_RIG_NOT_FOUND, + /// + /// SteamVR plugin Camera Rig controller not found. + /// + VR_CAMERA_RIG_CONTROLLER_NOT_FOUND, + /// + /// 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. + /// + PAD_CAMERA_CALIBRATION_NOT_FOUND, + /// + /// At least one VR controller must be detected. + /// + NOT_ENOUGH_PAD_DETECTED, + /// + /// SteamVR Unity plugin hasn't been imported. + /// + STEAMVR_NOT_INSTALLED, + /// + /// Oculus Integration Unity plugin hasn't been imported. + /// + OVR_NOT_INSTALLED, + /// + /// The ZED has been disconnected. (It was connected previously) + /// + ZED_IS_DISCONNECETD, + /// + /// The ZED SDK is not installed or a dependency is missing. + /// + SDK_NOT_INSTALLED, + /// + /// 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. + /// + SDK_DEPENDENCIES_ISSUE, + /// + /// Scanned mesh is too small to create a Nav Mesh. + /// + NAVMESH_NOT_GENERATED, + /// + /// The tracking system could not load the spatial memory area file. + /// + TRACKING_BASE_AREA_NOT_FOUND, + } + + + /// + /// 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 should be set to 16:9 aspect ratio"; + + case ERROR.TRACKING_NOT_INITIALIZED: + return "Error: Unable to initialize Tracking module"; + + case ERROR.CAMERA_NOT_INITIALIZED: + return "Unable to open camera"; + + case ERROR.UNABLE_TO_OPEN_CAMERA: + return "Camera not detected"; + + case ERROR.CAMERA_DETECTION_ISSUE: + return "Unable to open camera"; + + case ERROR.SENSOR_NOT_DETECTED: + return "Camera motion sensor not detected"; + + case ERROR.LOW_USB_BANDWIDTH : + return "Low USB bandwidth"; + + case ERROR.CAMERA_LOADING: + return "Loading camera..."; + + case ERROR.SDK_MODULE_LOADING: + return " Loading modules..."; + + case ERROR.VR_CAMERA_RIG_NOT_FOUND: + 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: 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 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 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: "; + + case ERROR.STEAMVR_NOT_INSTALLED: + return "Warning: SteamVR is not installed."; + + case ERROR.OVR_NOT_INSTALLED: + return "Warning: OVR Plugin is not installed."; + + case ERROR.ZED_IS_DISCONNECETD: + return "Camera disconnected"; + + case ERROR.SDK_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 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 Navigation Agent, or scan a wider zone."; + case ERROR.TRACKING_BASE_AREA_NOT_FOUND: + return "The tracking could not load the spatial memory area file."; + + + default: + return "Unknown error"; + } + + } + +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs.meta new file mode 100644 index 0000000..c8e433e --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDLogMessage.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 49bc778b041af8749b873d57639f27d7 +timeCreated: 1507318830 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs new file mode 100644 index 0000000..6ebdf28 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs @@ -0,0 +1,346 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// ##DEPRECATED + +using UnityEngine; + +#if UNITY_EDITOR +using UnityEditor; +#endif +/// +/// [Obsolete] 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). +/// [Obsolete] 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. +/// + +[System.Obsolete("SVO Management has been moved to ZEDManager directly. Not used anymore", true)] +public class ZEDSVOManager : MonoBehaviour +{ + /// + /// 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 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; + + /// + /// 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"; + + /// + /// 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("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 = false; + + /// + /// Current frame being read from the SVO. Doesn't apply when recording. + /// + [HideInInspector] + [SerializeField] + private int currentFrame = 0; + /// + /// Current frame being read from the SVO. Doesn't apply when recording. + /// + public int CurrentFrame + { + get + { + return currentFrame; + } + set + { + currentFrame = value; + } + } + + /// + /// Total number of frames in a loaded SVO. + /// + [HideInInspector] + [SerializeField] + private int numberFrameMax = 0; + /// + /// Total number of frames in a loaded SVO. + /// + public int NumberFrameMax + { + set + { + numberFrameMax = value; + } + get + { + return numberFrameMax; + } + } + + /// + /// Set true to pause the SVO reading or recording. Will not pause the Unity scene itself. + /// + [HideInInspector] + [SerializeField] + public bool pause = false; + + /// + /// 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.AVCHD_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; } + + /// + /// ZED Camera + /// + public sl.ZEDCamera zedCam; + + /// + /// 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) + { + zedCam = zedCamera; + if (record) + { + 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) + { + NumberFrameMax = zedCamera.GetSVONumberOfFrames(); + } + } + + + + +} + +#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. +/// +[System.Obsolete("SVO Management has been moved to ZEDManager directly. Not used anymore", true)] +[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; + private SerializedProperty loop; + private SerializedProperty videoFile; + private SerializedProperty currentFrame; + private SerializedProperty numberFrameMax; + + Rect drop_area; //Bounds for dragging and dropping SVO files. + + 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" }; //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(); + obj = (ZEDSVOManager)target; + EditorGUI.BeginChangeCheck(); + DrawDefaultInspector(); + + using (new EditorGUI.DisabledScope(Application.isPlaying)) + { + 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(); + 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(); + } + EditorGUILayout.EndHorizontal(); + if (drop_area.width != EditorGUIUtility.currentViewWidth || drop_area.height != Screen.height) + { + drop_area = new Rect(0, 0, EditorGUIUtility.currentViewWidth, Screen.height); + } + if (EditorGUI.EndChangeCheck()) + { + CheckChange(); + } + EditorGUI.BeginChangeCheck(); + + GUI.enabled = (obj.NumberFrameMax > 0); + GUIContent sliderlabel = new GUIContent("Frame ", "SVO playback position"); + currentFrame.intValue = EditorGUILayout.IntSlider(sliderlabel, currentFrame.intValue, 0, numberFrameMax.intValue); + if (EditorGUI.EndChangeCheck()) + { + if (obj.zedCam != null) + { + //If the slider of frame from the SVO has moved, manually grab the frame and update the textures. + obj.zedCam.SetSVOPosition(currentFrame.intValue); + if (pause.boolValue) + { + obj.NeedNewFrameGrab = true; + } + } + } + + GUI.enabled = false; + + if (obj.zedCam != null) + GUI.enabled = obj.zedCam.IsCameraReady; + + pauseText = pause.boolValue ? "Resume" : "Pause"; + GUIContent pauselabel = new GUIContent(pauseText, pauseText + pauseTooltip); + if (GUILayout.Button(pauselabel)) + { + pause.boolValue = !pause.boolValue; + } + GUI.enabled = true; + DropAreaGUI(); + + 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"); + record = serializedObject.FindProperty("record"); + read = serializedObject.FindProperty("read"); + loop = serializedObject.FindProperty("loop"); + + videoFile = serializedObject.FindProperty("videoFile"); + currentFrame = serializedObject.FindProperty("currentFrame"); + numberFrameMax = serializedObject.FindProperty("numberFrameMax"); + } + + /// + /// Allows looping when reading an SVO file (only) and prevents + /// reading and recording from both being true at the same time. + /// + private void CheckChange() + { + if (loop.boolValue && record.boolValue) + { + loop.boolValue = false; + } + if (read.boolValue && (current_readValue != read.boolValue)) + { + record.boolValue = false; + current_recordValue = false; + current_readValue = read.boolValue; + } + if (!read.boolValue && (current_readValue != read.boolValue)) + { + loop.boolValue = false; + } + if (record.boolValue && (current_recordValue != record.boolValue)) + { + read.boolValue = false; + current_readValue = false; + loop.boolValue = false; + current_recordValue = record.boolValue; + } + + } + + /// + /// Helper to get the name of a drag and dropped file. + /// + public void DropAreaGUI() + { + Event evt = Event.current; + ZEDSVOManager obj = (ZEDSVOManager)target; + switch (evt.type) + { + case EventType.DragUpdated: + case EventType.DragPerform: + if (!drop_area.Contains(evt.mousePosition)) + return; + DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + if (evt.type == EventType.DragPerform) + { + DragAndDrop.AcceptDrag(); + foreach (string dragged_object in DragAndDrop.paths) + { + videoFile.stringValue = dragged_object; + } + } + break; + } + } +} +#endif diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs.meta new file mode 100644 index 0000000..e9348be --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSVOManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d533f8f5ad2836d459869909806be714 +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs new file mode 100644 index 0000000..3e9d9fc --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs @@ -0,0 +1,634 @@ +using UnityEngine; +using System.Text; +using System.IO; + +/// +/// 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 **************************** + ***********************************************************************************************/ + public static bool IsVector3NaN(Vector3 input) + { + if (float.IsNaN (input.x) || float.IsNaN (input.y) || float.IsNaN (input.z)) + return true; + else + return false; + } + + /// + /// 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. + /// + /// 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(sl.ZEDCamera zedCam,Vector2 pixel, sl.REFERENCE_FRAME reference_frame, Camera cam, out Vector3 normal) + { + normal = Vector3.zero; + + if (zedCam == null) + return false; + + Vector4 n; + bool r = zedCam.GetNormalValue(new Vector3(pixel.x,pixel.y, 0), out n); + + switch (reference_frame) { + case sl.REFERENCE_FRAME.CAMERA: //Relative to the provided camera. + normal = n; + break; + + case sl.REFERENCE_FRAME.WORLD: //Relative to the world. + normal = cam.transform.TransformDirection(n); + break; + default : + normal = Vector3.zero; + break; + } + + return r; + } + + /// + /// 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(sl.ZEDCamera zedCam,Vector3 position, sl.REFERENCE_FRAME reference_frame,Camera cam, out Vector3 normal) + { + normal = Vector3.zero; + + if (zedCam == null) + return false; + + Vector4 n; + bool r = zedCam.GetNormalValue(cam.WorldToScreenPoint(position), out n); + + switch (reference_frame) { + case sl.REFERENCE_FRAME.CAMERA: + normal = n; + break; + + case sl.REFERENCE_FRAME.WORLD : + normal = cam.transform.TransformDirection(n); + break; + + default : + normal = Vector3.zero; + break; + } + + return r; + + } + + /// + /// 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(sl.ZEDCamera zedCam,Vector2 pixel, out float depth) + { + depth = 0.0f; + + if (zedCam == null) + return false; + + float d = zedCam.GetDepthValue(new Vector3(pixel.x, pixel.y, 0)); + depth = d; + + if (d == -1) return false; + return true; + } + + /// + /// 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(sl.ZEDCamera zedCam,Vector3 position, Camera cam, out float depth) + { + depth = 0.0f; + + if (zedCam == null) + return false; + + Vector3 pixelPosition = cam.WorldToScreenPoint (position); + + float d = zedCam.GetDepthValue(new Vector3(pixelPosition.x, pixelPosition.y, 0)); + depth = d; + + if (d == -1) return false; + return true; + } + + + + /// + /// 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(sl.ZEDCamera zedCam,Vector2 pixel, out float distance) + { + distance = 0.0f; + + if (zedCam == null) + return false; + + float d = zedCam.GetDistanceValue(new Vector3(pixel.x, pixel.y, 0)); + distance = d; + + if (d == -1) return false; + return true; + } + + + /// + /// 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(sl.ZEDCamera zedCam,Vector3 position, Camera cam, out float distance) + { + distance = 0.0f; + + if (zedCam == null) + return false; + + Vector3 pixelPosition = cam.WorldToScreenPoint (position); + + float d = zedCam.GetDistanceValue(new Vector3(pixelPosition.x, pixelPosition.y, 0)); + distance = d; + + if (d == -1) return false; + return true; + } + /// + /// Gets the world position of the given image pixel. + /// + /// 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(sl.ZEDCamera zedCam,Vector2 pixel, Camera cam, out Vector3 worldPos) + { + worldPos = Vector3.zero; + + if (zedCam == null) + return false; + + float d; + worldPos = Vector3.zero; + if (!GetForwardDistanceAtPixel(zedCam,pixel, out d)) return false; + + //Extract world position using screen-to-world transform. + worldPos = cam.ScreenToWorldPoint(new Vector3(pixel.x, pixel.y,d)); + return true; + } + + + /// + /// Checks if a real-world location 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. + /// 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(sl.ZEDCamera zedCam,Vector3 position, Camera cam) + { + if (zedCam == null) + return false; + + RaycastHit hit; + float d; + GetForwardDistanceAtWorldLocation(zedCam,position, cam,out d); + if (Physics.Raycast(cam.transform.position, position - cam.transform.position, out hit)) + { + if (hit.distance < d) return false; + } + return true; + } + + /// + /// 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(sl.ZEDCamera zedCam, Vector2 pixel, Camera cam) + { + if (zedCam == null) + return false; + + RaycastHit hit; + float d; + GetForwardDistanceAtPixel(zedCam, pixel,out d); + Vector3 position = cam.ScreenToWorldPoint(new Vector3(pixel.x, pixel.y, d)); + if (Physics.Raycast(cam.transform.position, position - cam.transform.position, out hit)) + { + if (hit.distance < d) return false; + } + return true; + } + + + + /*********************************************************************************************** + ******************** HIT TEST FUNCTIONS ****************************** + ***********************************************************************************************/ + + /// + /// 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. + /// + /// 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(sl.ZEDCamera zedCam, Camera camera, Vector3 point, bool countinvalidascollision = false, float realworldthickness = Mathf.Infinity) + { + if (zedCam == null) + return false; + + //Transform the point into screen space. + Vector3 screenpoint = camera.WorldToScreenPoint(point); + + //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. + float realdistance; + GetEuclideanDistanceAtPixel(zedCam, 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) + { + return countinvalidascollision; //We can't read the depth from that pixel. + } + + 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 (unless closer by more than realworldthickness). + } + 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. + /// 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(sl.ZEDCamera zedCam, Camera camera, Vector3 startpos, Quaternion rot, float maxdistance, float distbetweendots, out Vector3 collisionpoint, + bool countinvalidascollision = false, float realworldthickness = Mathf.Infinity) + { + collisionpoint = Vector3.zero; + + if (zedCam == null) + return false; + + //Check for occlusion in a series of dots, spaced apart evenly. + Vector3 lastvalidpoint = startpos; + for (float i = 0; i < maxdistance; i += distbetweendots) + { + Vector3 pointtocheck = rot * new Vector3(0f, 0f, i); + pointtocheck += startpos; + + bool hit = HitTestAtPoint(zedCam, camera, pointtocheck,countinvalidascollision, realworldthickness); + + if (hit) + { + //Return the last valid place before the collision. + collisionpoint = lastvalidpoint; + return true; + } + else + { + lastvalidpoint = pointtocheck; + } + } + + //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 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(sl.ZEDCamera zedCam, 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. + Vector3 randompoint = Random.onUnitSphere * radius + centerpoint; + if(HitTestAtPoint(zedCam, camera, randompoint, countinvalidascollision, realworldthickness)) + { + occludedpoints++; + } + } + + //See if the percentage of occluded pixels exceeds the threshold. + float occludedpercent = occludedpoints / (float)numberofsamples; + if (occludedpercent > blockedpercentagethreshold) + { + return true; //Occluded. + } + else return false; + } + + /// + /// 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(sl.ZEDCamera zedCam, 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. + //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); + + //Check the vertices in the mesh for a collision, skipping vertices to match the specified sample percentage. + int intersections = 0; + for(int i = 0; i < mesh.vertices.Length; i += checkfrequency) + { + if (HitTestAtPoint(zedCam, camera, worldtransform.TransformPoint(mesh.vertices[i]),countinvalidascollision, realworldthickness)) + { + intersections++; + } + } + + //See if our total collisions exceeds the threshold to call it a collision. + float blockedpercentage = (float)intersections / totalchecks; + if(blockedpercentage > blockedpercentagethreshold) + { + return true; + } + + return false; + } + + /// + /// 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(sl.ZEDCamera zedCam, Camera camera, MeshFilter meshfilter, float blockedpercentagethreshold, float meshsamplepercent = 1, + bool countinvalidascollision = false, float realworldthickness = Mathf.Infinity) + { + return HitTestOnMesh(zedCam, camera, meshfilter.mesh, meshfilter.transform, blockedpercentagethreshold, meshsamplepercent, countinvalidascollision, realworldthickness); + } + + /// + /// 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); + + + //Make sure it's within our view frustrum (except for clipping planes) + if (screenpoint.z <= 0f) + { + return false; //No collision if it's behind us. + } + + + if (screenpoint.x < 0f || //Too far to the left + screenpoint.y < 0f || //Too far to the bottom + screenpoint.x >= camera.pixelWidth || //Too far to the right + screenpoint.y >= camera.pixelHeight) //Too far to the top + { + return false; + } + + return true; + } + + + /*********************************************************************************************** + ****************************** IMAGE UTILS ********************************** + ***********************************************************************************************/ + + /// + /// 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; //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); //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; //Restore the old active RenderTexture. + return true; + } + + + + /*********************************************************************************************** + ****************************** MESH UTILS ********************************** + ***********************************************************************************************/ + public static string MeshToString(MeshFilter mf) + { + Mesh m = mf.mesh; + Material[] mats = mf.GetComponent().sharedMaterials; + + StringBuilder sb = new StringBuilder(); + + sb.Append("g ").Append(mf.name).Append("\n"); + foreach (Vector3 v in m.vertices) + { + sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z)); + } + sb.Append("\n"); + foreach (Vector3 v in m.normals) + { + sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z)); + } + sb.Append("\n"); + foreach (Vector3 v in m.uv) + { + sb.Append(string.Format("vt {0} {1}\n", v.x, v.y)); + } + for (int material = 0; material < m.subMeshCount; material++) + { + sb.Append("\n"); + sb.Append("usemtl ").Append(mats[material].name).Append("\n"); + sb.Append("usemap ").Append(mats[material].name).Append("\n"); + + int[] triangles = m.GetTriangles(material); + for (int i = 0; i < triangles.Length; i += 3) + { + sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", + triangles[i] + 1, triangles[i + 1] + 1, triangles[i + 2] + 1)); + } + } + return sb.ToString(); + } + + public static void MeshToFile(MeshFilter mf, string filename) + { + using (StreamWriter sw = new StreamWriter(filename)) + { + sw.Write(MeshToString(mf)); + } + } + + /*********************************************************************************************** + ****************************** MATH UTILS ********************************** + ***********************************************************************************************/ + + 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; + Vector3 vector2 = lineEnd - lineStart; + float magnitude = vector2.magnitude; + Vector3 lhs = vector2; + if (magnitude > 1E-06f) + { + lhs = (Vector3)(lhs / magnitude); + } + float num2 = Mathf.Clamp(Vector3.Dot(lhs, rhs), 0f, magnitude); + return (lineStart + ((Vector3)(lhs * num2))); + } + + + +} diff --git a/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs.meta new file mode 100644 index 0000000..9c02426 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Utilities/ZEDSupportFunctions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 43f797c09843a474282ec7ea25c3307c +timeCreated: 1509617155 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs b/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs new file mode 100644 index 0000000..549b295 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs @@ -0,0 +1,2401 @@ +using UnityEngine; +using System; +using System.Threading; +using UnityEngine.VR; +using System.Collections; +using System.Collections.Generic; + +#if UNITY_EDITOR +using UnityEditor; +#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 +{ + + /// + /// Static function to get instance of the ZEDManager with a given camera_ID. See sl.ZED_CAMERA_ID for the available choices. + /// + public static object grabLock; + static ZEDManager[] ZEDManagerInstance = null; + public static ZEDManager GetInstance(sl.ZED_CAMERA_ID _id) + { + if (ZEDManagerInstance == null) + return null; + else + return ZEDManagerInstance[(int)_id]; + } + + /// + /// Static function to get all ZEDManagers that have been properly instantiated. + /// Cameras may not necessarily be connected, if they haven't finished connecting, have disconnected, + /// or if no camera is available. + /// + /// + public static List GetInstances() + { + List instances = new List(); + for (int i = 0; i < (int)sl.Constant.MAX_CAMERA_PLUGIN; i++) + { + ZEDManager instance = GetInstance((sl.ZED_CAMERA_ID)i); + if (instance != null) + instances.Add(instance); + } + return instances; + } + + + /// + /// 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 = true; + + /// + /// Current instance of the ZED Camera, which handles calls to the Unity wrapper .dll. + /// + public sl.ZEDCamera zedCamera = null; + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////// Camera Settings /////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + /// + /// Resolution setting for all images retrieved from the camera. Higher resolution means lower framerate. + /// HD720 is strongly recommended for pass-through AR. + /// + + /// + /// Camera ID + /// + [HideInInspector] + public sl.ZED_CAMERA_ID cameraID = sl.ZED_CAMERA_ID.CAMERA_ID_01; + + /// + /// 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.")]*/ + [HideInInspector] + public sl.DEPTH_MODE depthMode = sl.DEPTH_MODE.PERFORMANCE; + + + /// + /// Input Type in SDK (USB, SVO or Stream) + /// + [HideInInspector] + public sl.INPUT_TYPE inputType = sl.INPUT_TYPE.INPUT_TYPE_USB; + /// + /// Camera Resolution + /// + [HideInInspector] + public sl.RESOLUTION resolution = sl.RESOLUTION.HD720; + /// + /// Targeted FPS, based on the resolution. VGA = 100, HD720 = 60, HD1080 = 30, HD2K = 15. + /// + [HideInInspector] + public int FPS = 60; + + /// + /// SVO Input FileName + /// + [HideInInspector] + public string svoInputFileName = ""; + + /// + /// SVO loop back option + /// + [HideInInspector] + public bool svoLoopBack = true; + + /// + /// SVO loop back option + /// + [HideInInspector] + public bool svoRealTimeMode = false; + + /// + /// Current frame being read from the SVO. Doesn't apply when recording. + /// + [HideInInspector] + [SerializeField] + private int currentFrame = 0; + /// + /// Current frame being read from the SVO. Doesn't apply when recording. + /// + public int CurrentFrame + { + get + { + return currentFrame; + } + set + { + currentFrame = value; + } + } + + /// + /// Total number of frames in a loaded SVO. + /// + [HideInInspector] + [SerializeField] + private int numberFrameMax = 0; + /// + /// Total number of frames in a loaded SVO. + /// + public int NumberFrameMax + { + set + { + numberFrameMax = value; + } + get + { + return numberFrameMax; + } + } + [HideInInspector] + [SerializeField] + public bool pauseSVOReading = false; + [HideInInspector] + public bool pauseLiveReading = false; + + /// + /// Ask a new frame is in pause (SVO only) + /// + [HideInInspector] + public bool NeedNewFrameGrab = false; + + /// + /// Streaming Input IP (v2.8) + /// + [HideInInspector] + public string streamInputIP = "127.0.0.1"; + + /// + /// Streaming Input Port (v2.8) + /// + [HideInInspector] + public int streamInputPort = 30000; + + + + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////// Motion Tracking /////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + /// + /// 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. + /// + [HideInInspector] + 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. + /// + [HideInInspector] + public bool enableSpatialMemory = true; + /// + /// 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. + /// + [HideInInspector] + public string pathSpatialMemory; + + /// + /// Estimate initial position by detecting the floor. + /// + [HideInInspector] + public bool estimateInitialPosition = true; + + + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////// Spatial Mapping /////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + /// + /// Resolution setting for the scan. A higher resolution creates more submeshes and uses more memory, but is more accurate. + /// + [HideInInspector] + public ZEDSpatialMapping.RESOLUTION mappingResolutionPreset = ZEDSpatialMapping.RESOLUTION.MEDIUM; + + /// + /// Maximum distance geometry can be from the camera to be scanned. Geometry scanned from farther away will be less accurate. + /// + [HideInInspector] + public ZEDSpatialMapping.RANGE mappingRangePreset = ZEDSpatialMapping.RANGE.MEDIUM; + + /// + /// Whether mesh filtering is needed. + /// + [HideInInspector] + public bool isMappingFilteringEnable = false; + + /// + /// Whether surface textures will be scanned and applied. Note that texturing will add further delay to the post-scan finalizing period. + /// + [HideInInspector] + public bool isMappingTextured = false; + + /// + /// Whether to save the mesh .obj and .area files once the scan is finished. + /// + [HideInInspector] + public bool saveMeshWhenOver = false; + + /// + /// Path to save the .obj and .area files. + /// + [HideInInspector] + public string meshPath = "Assets/ZEDMesh.obj"; + + /// + /// Filtering setting. More filtering results in fewer faces in the mesh, reducing both file size and accuracy. + /// + [HideInInspector] + public sl.FILTER meshFilterParameters; + + /// + /// Instance of the ZEDSpatialMapping class that handles the actual spatial mapping implementation within Unity. + /// + [HideInInspector] + private ZEDSpatialMapping spatialMapping = null; + public ZEDSpatialMapping GetSpatialMapping { get { return spatialMapping; } } + + /// + /// Whether the spatial mapping is currently scanning. + /// + public bool IsMappingRunning { get { return spatialMapping != null ? spatialMapping.IsRunning() : false; } } + + /// + /// List of the processed submeshes. This list isn't filled until StopSpatialMapping() is called. + /// + public List MappingChunkList { get { return spatialMapping != null ? spatialMapping.ChunkList : null; } } + + /// + /// Whether the mesh update thread is running. + /// + public bool IsMappingUpdateThreadRunning { get { return spatialMapping != null ? spatialMapping.IsUpdateThreadRunning : false; } } + + /// + /// Whether the spatial mapping was running but has been paused (not stopped) by the user. + /// + public bool IsMappingPaused { get { return spatialMapping != null ? spatialMapping.IsPaused : false; } } + + /// + /// Whether the mesh is in the texturing stage of finalization. + /// + public bool IsMappingTexturingRunning { get { return spatialMapping != null ? spatialMapping.IsTexturingRunning : false; } } + + /// + /// Gets a value indicating whether the spatial mapping display is enabled. + /// + public bool IsSpatialMappingDisplay { get { return spatialMapping != null ? spatialMapping.display : false; } } + + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////////// Rendering /////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + /// + /// Rendering paths available to the ZED with the corresponding Unity rendering path. + /// + public enum ZEDRenderingMode + { + FORWARD = RenderingPath.Forward, + DEFERRED = RenderingPath.DeferredShading + }; + + /// + /// When enabled, the real world can occlude (cover up) virtual objects that are behind it. + /// Otherwise, virtual objects will appear in front. + /// + [HideInInspector] + public bool depthOcclusion = true; + + /// + /// Enables post-processing effects on virtual objects that blends them in with the real world. + /// + [HideInInspector] + public bool postProcessing = true; + + /// + /// Field version of CameraBrightness property. + /// + [SerializeField] + [HideInInspector] + private int m_cameraBrightness = 100; + /// Brightness of the final real-world image. Default is 100. 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 int CameraBrightness + { + get { return m_cameraBrightness; } + set + { + if (m_cameraBrightness == value) return; + m_cameraBrightness = value; + if (OnCamBrightnessChange != null) + OnCamBrightnessChange(m_cameraBrightness); + } + } + + /// + /// Field version of MaxDepthRange property. + /// + [SerializeField] + [HideInInspector] + private float m_maxDepthRange = 20f; + /// + /// Maximum depth at which the camera will display the real world, in meters. Pixels further than this value will be invisible. + /// + public float MaxDepthRange + { + get { return m_maxDepthRange; } + set + { + if (m_maxDepthRange == value) return; + m_maxDepthRange = value; + if (OnMaxDepthChange != null) + OnMaxDepthChange(m_maxDepthRange); + } + } + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////// Recording Module ////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + /// + /// SVO Output file name + /// + [HideInInspector] + public string svoOutputFileName = "Assets/Recording.svo"; + + /// + /// SVO Compression mode used for recording + /// + [HideInInspector] + public sl.SVO_COMPRESSION_MODE svoOutputCompressionMode = sl.SVO_COMPRESSION_MODE.AVCHD_BASED; + + /// + /// Indicates if frame must be recorded + /// + [HideInInspector] + public bool needRecordFrame = false; + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////// Streaming Module ////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + /// + /// Enable/Disable Streaming module + /// + [HideInInspector] + public bool enableStreaming = false; + /// + /// Status of streaming request + /// + private bool isStreamingEnable = false; + + /// + /// Codec used for Streaming + /// + [HideInInspector] + public sl.STREAMING_CODEC streamingCodec = sl.STREAMING_CODEC.AVCHD_BASED; + + /// + /// port used for Streaming + /// + [HideInInspector] + public int streamingPort = 30000; + + /// + /// bitrate used for Streaming + /// + [HideInInspector] + public int bitrate = 8000; + + /// + /// gop size used for Streaming + /// + [HideInInspector] + public int gopSize = -1; + + /// + /// Enable/Disable adaptative bitrate + /// + [HideInInspector] + public bool adaptativeBitrate = false; + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////// Advanced control ///////////////////////////// + ///////////////////////////////////////////////////////////////////////// + /// + /// + /// True to make the ZED image fade from black when the application starts. + /// + [HideInInspector] + public bool fadeInOnStart = true; + /// + /// True to apply DontDestroyOnLoad() on the ZED rig in Awake(), preserving it between scenes. + /// + [HideInInspector] + public bool dontDestroyOnLoad = false; + + /// + /// Grey Out Skybox on Start", "True to set the background to a neutral gray when the scene starts. + /// Recommended for AR so that lighting on virtual objects better matches the real world. + /// + [HideInInspector] + public bool greySkybox = true; + + /// + /// Field version of confidenceThreshold property. + /// + [SerializeField] + [HideInInspector] + private int m_confidenceThreshold = 100; + /// + /// How tolerant the ZED SDK is to low confidence values. Lower values filter more pixels. + /// + public int confidenceThreshold + { + get + { + return m_confidenceThreshold; + } + set + { + if (value == m_confidenceThreshold) return; + + m_confidenceThreshold = Mathf.RoundToInt(Mathf.Clamp(value, 0, 100)); + if (Application.isPlaying && zedReady) + { + zedCamera.SetConfidenceThreshold(m_confidenceThreshold); + } + + } + } + + /// + /// Delegate for OnCamBrightnessChange, which is used to update shader properties when the brightness setting changes. + /// + public delegate void onCamBrightnessChangeDelegate(int newVal); + /// + /// Event fired when the camera brightness setting is changed. Used to update shader properties. + /// + public event onCamBrightnessChangeDelegate OnCamBrightnessChange; + /// + /// Delegate for OnCamBrightnessChange, which is used to update shader properties when the max depth setting changes. + /// + public delegate void onMaxDepthChangeDelegate(float newVal); + /// + /// Event fired when the max depth setting is changed. Used to update shader properties. + /// + public event onMaxDepthChangeDelegate OnMaxDepthChange; + + /// + /// Whether to show the hidden camera rig used in stereo AR mode to prepare images for HMD output. + /// + [SerializeField] + [HideInInspector] + private bool showarrig = false; + /// + /// Whether to show the hidden camera rig used in stereo AR mode to prepare images for HMD output. + /// This is rarely needed, but can be useful for understanding how the ZED output works. + /// + public bool showARRig + { + get + { + return showarrig; + } + set + { + if (Application.isPlaying && showarrig != value && zedRigDisplayer != null) + { + zedRigDisplayer.hideFlags = value ? HideFlags.None : HideFlags.HideInHierarchy; + } + + showarrig = value; + } + } + + private float maxdepthrange = 20f; + public float maxDepthRange + { + get + { + return maxdepthrange; + } + set + { + maxdepthrange = Mathf.Clamp(value, 0, 20); + if (Application.isPlaying) + { + setRenderingSettings(); + } + } + } + + + ///////////////////////////////////////////////////////////////////////// + ///////////////////////// Status Report ///////////////////////////////// + ///////////////////////////////////////////////////////////////////////// + + //Strings used for the Status display in the Inspector. + [Header("Status")] + /// + /// The camera model (ZED or ZED-M). + /// + [ReadOnly("Camera S/N")] [HideInInspector] public string cameraModel = "-"; + /// + /// The camera serial number. + /// + [ReadOnly("Camera S/N")] [HideInInspector] public string cameraSerialNumber = "-"; + /// + /// The camera firmware version + /// + [ReadOnly("Camera Firmware")] [HideInInspector] public string cameraFirmware = "-"; + /// + /// Version of the installed ZED SDK, for display in the Inspector. + /// + [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 /////////// + //////////////////////////// + /// + /// 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 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; + /// + /// 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; + /// + /// Disable the IMU of the ZED-M + /// + private bool cameraDisableIMU = false; + /// + /// Set the camera in Flip mode + /// + private bool cameraFlipMode = false; + /// + /// Whether the camera is currently being tracked using the ZED's inside-out tracking. + /// + private bool isZEDTracked = false; + /// + /// Whether the ZED's inside-out tracking has been activated. + /// + private bool isTrackingEnable = false; + /// + /// 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; } + } + + /// + /// Whether the camera has a new frame available. + /// + private bool isNewFrameGrabbed = false; + /// + /// Public accessor for whether the camera has a new frame available. + /// + public bool IsNewFrameGrabbed + { + get { return isNewFrameGrabbed; } + } + + /// + /// Orientation last returned by the ZED's tracking. + /// + private Quaternion zedOrientation = Quaternion.identity; + /// + /// Position last returned by the ZED's tracking. + /// + private Vector3 zedPosition = Vector3.zero; + + /// + /// Position of the camera (zedRigRoot) when the scene starts. Not used in Stereo AR. + /// + private Vector3 initialPosition = new Vector3(); + /// + /// Orientation of the camera (zedRigRoot) when the scene starts. Not used in Stereo AR. + /// + private Quaternion initialRotation = Quaternion.identity; + /// + /// 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. + /// + [SerializeField] + [HideInInspector] + public sl.SENSING_MODE sensingMode = sl.SENSING_MODE.FILL; + /// + /// Rotation offset used to retrieve the tracking with a rotational offset. + /// + private Quaternion rotationOffset; + /// + /// Position offset used to retrieve the tracking with a positional offset. + /// + private Vector3 positionOffset; + /// + /// Enables pose smoothing during drift correction. Leave it to true. + /// + private bool enablePoseSmoothing = true; + /// + /// The engine FPS, updated every frame. + /// + private float fps_engine = 90.0f; + + /// + /// Recording state + /// + private bool isRecording = false; + + /////////////////////////////////////// + /////////// Static States ///////////// + /////////////////////////////////////// + + /// + /// Whether AR mode is activated. + /// + private 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 bool IsStereoRig + { + get { return isStereoRig; } + } + + /// + /// Checks if the ZED has finished initializing. + /// + private bool zedReady = false; + /// + /// Checks if the ZED has finished initializing. + /// + public bool IsZEDReady + { + get { return zedReady; } + } + + /// + /// 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 the tracking has started (whether via ZED or a VR HMD). + /// + public Vector3 OriginPosition { get; private set; } + /// + /// First rotation/orientation registered after the tracking has started (whether via ZED or a VR HMD). + /// + public Quaternion OriginRotation { get; private set; } + + /// + /// In AR pass-through mode, whether to compare the ZED's IMU data against the reported position of + /// the VR headset. This helps compensate for drift and should usually be left on. + /// However, in some setups, like when using a custom mount, this can cause tracking errors. + /// + /// Read more about the potential errors here: https://support.stereolabs.com/hc/en-us/articles/360026482413 + /// + public bool setIMUPriorInAR = true; + + /////////////////////////////////////////////////// + [HideInInspector] public Quaternion gravityRotation = Quaternion.identity; + [HideInInspector] public Vector3 ZEDSyncPosition; + [HideInInspector] public Vector3 HMDSyncPosition; + [HideInInspector] public Quaternion ZEDSyncRotation; + [HideInInspector] public Quaternion HMDSyncRotation; + + + /// + /// Image acquisition thread. + /// + private Thread threadGrab = null; + /// + /// State of the image acquisition thread. + /// + private bool running = false; + + /// + /// Initialization thread. + /// + private Thread threadOpening = null; + /// + /// Result of the latest attempt to initialize the ZED. + /// + private sl.ERROR_CODE lastInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; + public sl.ERROR_CODE LastInitStatus { get { return lastInitStatus; } } + /// + /// State of the ZED initialization thread. + /// + private bool openingLaunched; + + /// + /// Wait Handle used to safely tell the init thread to shut down. + /// + EventWaitHandle initQuittingHandle; + /// + /// When true, the init thread will close early instead of completing all its connection attempts. + /// Set to true when the application is closed before a camera finishes its initialization. + /// + private bool forceCloseInit = false; + + /// + /// Tracking initialization thread. Used as the tracking takes some time to start. + /// + private Thread trackerThread = null; + + + /////////////////////////////////////////// + ////// Camera and Player Transforms ////// + /////////////////////////////////////////// + /// + /// Transform of the left camera in the ZED rig. + /// + private Transform camLeftTransform = null; + + /// + /// Transform of the right camera in the ZED rig. Only exists in a stereo rig (like ZED_Rig_Stereo). + /// + private Transform camRightTransform = null; + + /// + /// 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; + + /// + /// Left camera in the ZED rig. Also the "main" camera if in ZED_Rig_Mono. + /// + private Camera cameraLeft; + + /// + /// Right camera of the ZED rig. Only exists in a stereo rig (like ZED_Rig_Stereo). + /// + private Camera cameraRight; + + + /// + /// 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; + } + + /// + /// Returns the left ZED camera transform. If there is no left camera but there is a right camera, + /// returns the right camera transform instead. + /// + /// + public Transform GetMainCameraTransform() + { + if (camLeftTransform) return camLeftTransform; + else if (camRightTransform) return camRightTransform; + else return null; + } + + /// + /// Gets the left camera transform in the ZED rig. It's best to use this one as it's available in all configurations. + /// + public Transform GetLeftCameraTransform() + { + return camLeftTransform; + } + + /// + /// Get the right camera transform in the ZED rig. Only available in the stereo rig (ZED_Rig_Stereo). + /// + public Transform GetRightCameraTransform() + { + return camRightTransform; + } + + /// + /// Returns the left ZED camera. If there is no left camera but there is a right camera, + /// returns the right camera instead. + /// + /// + public Camera GetMainCamera() + { + if (cameraLeft) return cameraLeft; + else if (cameraRight) return cameraRight; + else return null; + } + + /// + /// Gets the left camera in the ZED rig. Both ZED_Rig_Mono and ZED_Rig_Stereo have a left camera by default. + /// + public Camera GetLeftCamera() + { + if (cameraLeft == null && camLeftTransform != null) + cameraLeft = camLeftTransform.GetComponent(); + return cameraLeft; + } + + /// + /// Get the right camera in the ZED rig. Only available in the stereo rig (ZED_Rig_Stereo) unless configured otherwise. + /// + public Camera GetRightCamera() + { + if (cameraRight == null && camRightTransform != null) + cameraRight = camRightTransform.GetComponent(); + return cameraRight; + } + + + /// + /// Save the foldout options as it was used last time + /// + [SerializeField] + [HideInInspector] + private bool advancedPanelOpen = false; + [SerializeField] + [HideInInspector] + private bool spatialMappingFoldoutOpen = false; + [SerializeField] + [HideInInspector] + private bool recordingFoldoutOpen = false; + [SerializeField] + [HideInInspector] + private bool streamingOutFoldoutOpen = false; + [SerializeField] + [HideInInspector] + private bool camControlFoldoutOpen = false; + + ///////////////////////////////////// + ////// 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; + + + + ///////////////////////////////////// + ////// Layers for ZED ////// + ///////////////////////////////////// + + /// + /// Layer assigned to the cameras and objects of a (normally hidden) AR camera rig created to handle + /// pass-through AR. This allows the cameras to see nothing but two canvas objects with the final MR images. + /// + [HideInInspector] + public int arLayer + { + get + { + return arlayer; + } + } + [SerializeField] + [HideInInspector] + private int arlayer = 30; + + ///////////////////////////////////// + ////// 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 event OnZEDManagerReady OnZEDReady; + + /// + /// Delegate for OnZEDDisconnected. + /// + public delegate void OnZEDManagerDisconnected(); + /// + /// Event called when ZED was running but became disconnected. + /// + public event OnZEDManagerDisconnected OnZEDDisconnected; + + /// + /// Delegate for new Frame grabbed for external module update + /// + public delegate void OnGrabAction(); + /// + /// Event called when ZED has grabbed a new frame. + /// + public event OnGrabAction OnGrab; + + + #region CHECK_AR + /// + /// 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. + /// + private void CheckStereoMode() + { + zedRigRoot = gameObject.transform; //The object moved by tracking. By default it's this Transform. May get changed. + + bool devicePresent = UnityEngine.XR.XRDevice.isPresent; //May not need. + + //Set first left eye + Component[] cams = gameObject.GetComponentsInChildren(); + //Camera firstmonocam = null; + List monocams = new List(); + foreach (Camera cam in cams) + { + switch (cam.stereoTargetEye) + { + case StereoTargetEyeMask.Left: + if (!cameraLeft) + { + cameraLeft = cam; + camLeftTransform = cam.transform; + } + break; + case StereoTargetEyeMask.Right: + if (!cameraRight) + { + cameraRight = cam; + camRightTransform = cam.transform; + } + break; + case StereoTargetEyeMask.None: + monocams.Add(cam); + break; + case StereoTargetEyeMask.Both: + default: + break; + } + } + + //If the left camera or right camera haven't been assigned via stereo target eyes, search the monocams + //based on their ZEDRenderingPlane assignments. + //This won't affect whether the rig is in stereo mode, but allows the cameras to be accessed via GetLeftCamera() and GetRightCamera(). + if (cameraLeft == null || cameraRight == null) + { + foreach(Camera cam in monocams) + { + ZEDRenderingPlane rendplane = cam.gameObject.GetComponent(); + if (!rendplane) continue; + + if(!cameraLeft && (rendplane.viewSide == ZEDRenderingPlane.ZED_CAMERA_SIDE.LEFT || rendplane.viewSide == ZEDRenderingPlane.ZED_CAMERA_SIDE.LEFT_FORCE)) + { + cameraLeft = cam; + camLeftTransform = cam.transform; + } + else if(!cameraRight && (rendplane.viewSide == ZEDRenderingPlane.ZED_CAMERA_SIDE.RIGHT || rendplane.viewSide == ZEDRenderingPlane.ZED_CAMERA_SIDE.RIGHT_FORCE)) + { + cameraRight = cam; + camRightTransform = cam.transform; + } + } + } + + if (camLeftTransform && camRightTransform && cameraLeft.stereoTargetEye == StereoTargetEyeMask.Left) //We found both a left- and right-eye camera. + { + isStereoRig = UnityEngine.XR.XRDevice.isPresent; + if (camLeftTransform.transform.parent != null) + { + zedRigRoot = camLeftTransform.parent; //Make the camera's parent object (Camera_eyes in the ZED_Rig_Stereo prefab) the new zedRigRoot to be tracked. + } + + if (UnityEngine.XR.XRDevice.isPresent) + { + isStereoRig = true; + } + else + { + isStereoRig = false; + //If there's no VR headset, then cameras set to Left and Right won't display in Unity. Set them both to None. + if (cameraLeft) cameraLeft.stereoTargetEye = StereoTargetEyeMask.None; + if (cameraRight) cameraRight.stereoTargetEye = StereoTargetEyeMask.None; + } + + } + else //Not all conditions for a stereo rig were met. + { + isStereoRig = false; + + if (camLeftTransform) + { + Camera caml = camLeftTransform.gameObject.GetComponent(); + cameraLeft = caml; + + if (camLeftTransform.transform.parent != null) + zedRigRoot = camLeftTransform.parent; + } + else + { + zedRigRoot = transform; + } + } + } + #endregion + + + /// + /// 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; + foreach (Transform trans in go.GetComponentsInChildren(true)) + { + trans.gameObject.layer = layerNumber; + } + } + + + /// + /// Stops the initialization and grabbing threads. + /// + public void Destroy() + { + running = false; + + //In case the opening thread is still running. + if (threadOpening != null) + { + initQuittingHandle.Reset(); + forceCloseInit = true; + initQuittingHandle.Set(); + + threadOpening.Join(); + threadOpening = null; + } + + //Shut down the image grabbing thread. + if (threadGrab != null) + { + threadGrab.Join(); + threadGrab = null; + } + + if (IsMappingRunning) + StopSpatialMapping(); + + + Thread.Sleep(10); + } + + /// + /// Called by Unity when the application is closed. + /// Also called by Reset() to properly start from a 'clean slate.' + /// + void OnApplicationQuit() + { + + CloseManager(); + //sl.ZEDCamera.UnloadPlugin(); + + //If this was the last camera to close, make sure all instances are closed. + bool notlast = false; + foreach (ZEDManager manager in ZEDManagerInstance) + { + if (manager != null && manager.IsZEDReady == true) + { + notlast = true; + break; + } + } + if (notlast == false) + { + sl.ZEDCamera.UnloadPlugin(); + } + + } + + private void CloseManager() + { + if (spatialMapping != null) + spatialMapping.Dispose(); + + ClearRendering(); + + zedReady = false; + OnCamBrightnessChange -= SetCameraBrightness; + OnMaxDepthChange -= SetMaxDepthRange; + Destroy(); //Close the grab and initialization threads. + + if (zedCamera != null) + { + if (isRecording) + { + zedCamera.DisableRecording(); + } + zedCamera.Destroy(); + zedCamera = null; + } + +#if UNITY_EDITOR //Prevents building the app otherwise. + //Restore the AR layers that were hidden, if necessary. + + if (!showarrig) + { + LayerMask layerNumberBinary = (1 << arLayer); //Convert layer index into binary number. + UnityEditor.Tools.visibleLayers |= (layerNumberBinary); + } +#endif + + + sl.ZEDCamera.UnloadInstance((int)cameraID); + } + + private void ClearRendering() + { + if (camLeftTransform != null) + { + ZEDRenderingPlane leftRenderingPlane = camLeftTransform.GetComponent(); + if (leftRenderingPlane) + { + leftRenderingPlane.Clear(); + } + } + + if (IsStereoRig) + { + ZEDRenderingPlane rightRenderingPlane = GetRightCameraTransform().GetComponent(); + rightRenderingPlane.Clear(); + } + + + } + + + /// + /// Sets up starting properties and starts the ZED initialization co-routine. + /// + void Awake() + { + + // If never initialized, init the array of instances linked to each ZEDManager that could be created. + if (ZEDManagerInstance == null) + { + ZEDManagerInstance = new ZEDManager[(int)sl.Constant.MAX_CAMERA_PLUGIN]; + for (int i = 0; i < (int)sl.Constant.MAX_CAMERA_PLUGIN; i++) + ZEDManagerInstance[i] = null; + } + + + initialPosition = transform.localPosition; + initialRotation = transform.localRotation; + + zedReady = false; + ZEDManagerInstance[(int)cameraID] = this; + zedCamera = new sl.ZEDCamera(); + LayerHandler.GetInstance().setUsed(cameraID, true); + if (dontDestroyOnLoad) DontDestroyOnLoad(transform.root); //If you want the ZED rig not to be destroyed when loading a scene. + + //Set first few parameters for initialization. This will get passed to the ZED SDK when initialized. + initParameters = new sl.InitParameters(); + initParameters.resolution = resolution; + initParameters.cameraFPS = FPS; + initParameters.cameraID = (int)cameraID; + initParameters.depthMode = depthMode; + initParameters.depthStabilization = depthStabilizer; + initParameters.cameraDisableIMU = cameraDisableIMU; + initParameters.cameraImageFlip = cameraFlipMode; + + //Check if this rig is a stereo rig. Will set isStereoRig accordingly. + CheckStereoMode(); + + //Set initialization parameters that may change depending on what was done in CheckStereoMode(). + isZEDTracked = enableTracking; + zedPosition = initialPosition; + zedOrientation = initialRotation; + + lastInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; + + bool res = zedCamera.CreateCamera((int)cameraID, wrapperVerbose); + if (!res) + { + Debug.LogError("ZEDManager on " + gameObject.name + " couldn't connect to camera: " + cameraID + + ". Check if another ZEDManager is already connected."); + this.gameObject.SetActive (false); + return; + } + initParameters.inputType = inputType; + if (inputType == sl.INPUT_TYPE.INPUT_TYPE_USB) + { + } + else if (inputType == sl.INPUT_TYPE.INPUT_TYPE_SVO) + { + initParameters.pathSVO = svoInputFileName; + initParameters.svoRealTimeMode = svoRealTimeMode; + } + else if (inputType == sl.INPUT_TYPE.INPUT_TYPE_STREAM) + { + initParameters.ipStream = streamInputIP; + initParameters.portStream = (ushort)streamInputPort; + } + + versionZED = "[SDK]: " + sl.ZEDCamera.GetSDKVersion().ToString() + " [Plugin]: " + sl.ZEDCamera.PluginVersion.ToString(); + + + //Behavior specific to AR pass-through mode. + if (isStereoRig) + { + //Creates a hidden camera rig that handles final output to the headset. + GameObject o = CreateZEDRigDisplayer(); + if (!showarrig) o.hideFlags = HideFlags.HideInHierarchy; + o.transform.parent = transform; + + //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. + + //For the Game/output window, mirror the headset view using a custom script that avoids stretching. + CreateMirror(); + } + + //Starts a coroutine that initializes the ZED without freezing the game. + lastInitStatus = sl.ERROR_CODE.ERROR_CODE_LAST; + openingLaunched = false; + StartCoroutine(InitZED()); + + + OnCamBrightnessChange += SetCameraBrightness; //Subscribe event for adjusting brightness setting. + OnMaxDepthChange += SetMaxDepthRange; + + //Create Module Object + //Create the spatial mapping module object (even if not used necessarly) + spatialMapping = new ZEDSpatialMapping(transform, this); + + } + + + void Start() + { + //adjust layers for multiple camera + //setLayersForMultiCamera (); + } + + #region INITIALIZATION + //const int MAX_OPENING_TRIES = 10; + private uint numberTriesOpening = 0;/// Counter of tries to open the ZED + /// + /// ZED opening function. Should be called in the initialization thread (threadOpening). + /// + private void OpenZEDInBackground() + { + openingLaunched = true; + int timeout = 0; + + do + { + initQuittingHandle.WaitOne(0); //Makes sure we haven't been turned off early, which only happens in Destroy() from OnApplicationQuit(). + if (forceCloseInit) break; + + lastInitStatus = zedCamera.Init(ref initParameters); + timeout++; + numberTriesOpening++; + } while (lastInitStatus != sl.ERROR_CODE.SUCCESS); + } + + /// + /// Initialization coroutine. + /// + + private System.Collections.IEnumerator InitZED() + { + zedReady = false; + if (!openingLaunched) + { + initQuittingHandle = new EventWaitHandle(true, EventResetMode.ManualReset); + threadOpening = new Thread(new ThreadStart(OpenZEDInBackground)); //Assign thread. + threadOpening.Start(); + } + + while (lastInitStatus != sl.ERROR_CODE.SUCCESS) + { + yield return new WaitForSeconds(0.3f); + } + + + + //ZED has initialized successfully. + if (lastInitStatus == sl.ERROR_CODE.SUCCESS) + { + + threadOpening.Join(); + //Initialize the tracking thread, AR initial transforms and SVO read/write as needed. + ZEDReady(); + + //If using tracking, wait until the tracking thread has been initialized. + while (enableTracking && !isTrackingEnable) + { + yield return new WaitForSeconds(0.5f); + } + + //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) + { + Debug.LogWarning(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.SCREEN_RESOLUTION)); + } + + //get informations from camera (S/N, firmware, model...) + cameraModel = zedCamera.GetCameraModel().ToString(); + cameraFirmware = zedCamera.GetZEDFirmwareVersion().ToString(); + cameraSerialNumber = zedCamera.GetZEDSerialNumber().ToString(); + + if (inputType == sl.INPUT_TYPE.INPUT_TYPE_SVO) + { + numberFrameMax = zedCamera.GetSVONumberOfFrames(); + } + + // If streaming has been switched on before play + if (enableStreaming && !isStreamingEnable) + { + lock (zedCamera.grabLock) + { + sl.ERROR_CODE err = zedCamera.EnableStreaming(streamingCodec, (uint)bitrate, (ushort)streamingPort, gopSize, adaptativeBitrate); + if (err == sl.ERROR_CODE.SUCCESS) + { + isStreamingEnable = true; + } + else + { + enableStreaming = false; + isStreamingEnable = false; + } + } + } + + //If not already launched, launch the image grabbing thread. + if (!running) + { + + running = true; + requestNewFrame = true; + + threadGrab = new Thread(new ThreadStart(ThreadedZEDGrab)); + threadGrab.Start(); + + } + + zedReady = true; + isDisconnected = false; //In case we just regained connection. + + 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) 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 && UnityEngine.XR.XRDevice.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 by offsetHmdZEDPosition to compensate for the ZED's position on the headset. + //If values are wrong, tweak calibration file created in ZEDMixedRealityPlugin. + camLeftTransform.localPosition = arRig.HmdToZEDCalibration.translation; + camLeftTransform.localRotation = arRig.HmdToZEDCalibration.rotation; + if (camRightTransform) camRightTransform.localPosition = camLeftTransform.localPosition + rightCameraOffset; //Space the eyes apart. + if (camRightTransform) camRightTransform.localRotation = camLeftTransform.localRotation; + } + else if (isStereoRig && !UnityEngine.XR.XRDevice.isPresent) //Using stereo rig, but no VR headset. + { + //When no VR HMD is available, simply put the origin at the left camera. + if(camLeftTransform) camLeftTransform.localPosition = Vector3.zero; + if (camLeftTransform) camLeftTransform.localRotation = Quaternion.identity; + if (camRightTransform) camRightTransform.localPosition = rightCameraOffset; //Space the eyes apart. + if (camRightTransform) camRightTransform.localRotation = Quaternion.identity; + } + else //Using mono rig (ZED_Rig_Mono). No offset needed. + { + if (GetMainCameraTransform()) + { + GetMainCameraTransform().localPosition = Vector3.zero; + GetMainCameraTransform().localRotation = Quaternion.identity; + } + } + } + + /// + /// 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 leftRenderingPlane = null; + if (GetLeftCameraTransform() != null) + { + leftRenderingPlane = GetLeftCameraTransform().GetComponent(); + leftRenderingPlane.SetPostProcess(postProcessing); + cameraLeft.renderingPath = RenderingPath.UsePlayerSettings; + } + + ZEDRenderingPlane rightRenderingPlane = null; + if (GetRightCameraTransform() != null) + { + rightRenderingPlane = GetRightCameraTransform().GetComponent(); + rightRenderingPlane.SetPostProcess(postProcessing); + cameraRight.renderingPath = RenderingPath.UsePlayerSettings; + } + + SetCameraBrightness(m_cameraBrightness); + SetMaxDepthRange(m_maxDepthRange); + + Camera maincam = GetMainCamera(); + if (maincam != null) + { + ZEDRenderingMode renderingPath = (ZEDRenderingMode)maincam.actualRenderingPath; + + //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"); + if(cameraLeft) cameraLeft.renderingPath = RenderingPath.Forward; + if (cameraRight) cameraRight.renderingPath = RenderingPath.Forward; + } + + //Set depth occlusion. + if (renderingPath == ZEDRenderingMode.FORWARD) + { + if (leftRenderingPlane) + leftRenderingPlane.ManageKeywordPipe(!depthOcclusion, "NO_DEPTH_OCC"); + if (rightRenderingPlane) + rightRenderingPlane.ManageKeywordPipe(!depthOcclusion, "NO_DEPTH_OCC"); + + } + else if (renderingPath == ZEDRenderingMode.DEFERRED) + { + if (leftRenderingPlane) + 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 reference frame. If we need normals in the world frame, better to do the conversion ourselves. + runtimeParameters.measure3DReferenceFrame = sl.REFERENCE_FRAME.CAMERA; + + while (running) + { + if (zedCamera == null) + return; + + if (runtimeParameters.sensingMode != sensingMode) runtimeParameters.sensingMode = sensingMode; + + AcquireImages(); + } + } + + + /// + /// Grabs images from the ZED SDK and updates tracking, FPS and timestamp values. + /// Called from ThreadedZEDGrab() in a separate thread. + /// + private void AcquireImages() + { + if (requestNewFrame && zedReady) + { + sl.ERROR_CODE e = sl.ERROR_CODE.FAILURE; + if (inputType == sl.INPUT_TYPE.INPUT_TYPE_SVO) + { + //handle pause + if (NeedNewFrameGrab && pauseSVOReading) + { + e = zedCamera.Grab(ref runtimeParameters); + NeedNewFrameGrab = false; + } + else if (!pauseSVOReading) + e = zedCamera.Grab(ref runtimeParameters); + + currentFrame = zedCamera.GetSVOPosition(); + } + else if (!pauseLiveReading) + { + e = zedCamera.Grab(ref runtimeParameters); + } + + + lock (zedCamera.grabLock) + { + if (e == sl.ERROR_CODE.CAMERA_NOT_DETECTED) + { + Debug.Log("Camera not detected or disconnected."); + isDisconnected = true; + Thread.Sleep(10); + requestNewFrame = false; + } + else if (e == sl.ERROR_CODE.SUCCESS) + { +#if UNITY_EDITOR + float camera_fps = zedCamera.GetCameraFPS(); + cameraFPS = camera_fps.ToString() + " FPS"; +#endif + //Get position of camera + if (isTrackingEnable) + { + zedtrackingState = zedCamera.GetPosition(ref zedOrientation, ref zedPosition, sl.TRACKING_FRAME.LEFT_EYE); + } + else + { + zedtrackingState = sl.TRACKING_STATE.TRACKING_OFF; + } + + if (needRecordFrame) + zedCamera.Record(); + + // Indicate that a new frame is available and pause the thread until a new request is called + newFrameAvailable = true; + requestNewFrame = false; + } + else + Thread.Sleep(1); + } + } + else + { + //To avoid "overheating." + Thread.Sleep(1); + } + } + #endregion + + /// + /// Initialize the SVO, and launch the thread to initialize tracking. Called once the ZED + /// is initialized successfully. + /// + private void ZEDReady() + { + FPS = (int)zedCamera.GetRequestedCameraFPS(); + if (enableTracking) + { + trackerThread = new Thread(EnableTrackingThreaded); + trackerThread.Start(); + } + else if (estimateInitialPosition) + { + sl.ERROR_CODE err = zedCamera.EstimateInitialPosition(ref initialRotation, ref initialPosition); + if (zedCamera.GetCameraModel() == sl.MODEL.ZED_M) + zedCamera.GetInternalIMUOrientation(ref initialRotation, sl.TIME_REFERENCE.IMAGE); + + if (err != sl.ERROR_CODE.SUCCESS) + Debug.LogWarning("Failed to estimate initial camera position"); + } + + if (enableTracking) + trackerThread.Join(); + + + if (isStereoRig && UnityEngine.XR.XRDevice.isPresent) + { + ZEDMixedRealityPlugin.Pose pose = arRig.InitTrackingAR(); + OriginPosition = pose.translation; + OriginRotation = pose.rotation; + + if (!zedCamera.IsHmdCompatible && zedCamera.IsCameraReady) + Debug.LogWarning("WARNING: AR Passtrough with a ZED is not recommended. Consider using ZED Mini, designed for this purpose."); + } + else + { + OriginPosition = initialPosition; + OriginRotation = initialRotation; + } + + //Set the original transform for the Rig + zedRigRoot.localPosition = OriginPosition; + zedRigRoot.localRotation = OriginRotation; + + //Set confidence threshold if needed. + if (m_confidenceThreshold != 100) zedCamera.SetConfidenceThreshold(m_confidenceThreshold); + +#if UNITY_EDITOR + UnityEditor.EditorApplication.playmodeStateChanged = HandleOnPlayModeChanged; +#endif + } + + /// + /// Initializes the ZED's inside-out tracking. Started as a separate thread in OnZEDReady. + /// + void EnableTrackingThreaded() + { + lock (zedCamera.grabLock) + { + //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 zedOrientation, ref zedPosition, enableSpatialMemory, + enablePoseSmoothing, estimateInitialPosition, pathSpatialMemory) == sl.ERROR_CODE.SUCCESS))) + { + throw new Exception(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.TRACKING_NOT_INITIALIZED)); + } + else + { + isTrackingEnable = true; + } + } + } + + +#if UNITY_EDITOR + /// + /// Handler for playmodeStateChanged. + /// + void HandleOnPlayModeChanged() + { + + if (zedCamera == null) return; + +#if UNITY_EDITOR + UnityEditor.EditorApplication.playmodeStateChanged = HandleOnPlayModeChanged; +#endif + } +#endif + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////// ENGINE UPDATE REGION ///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #region ENGINE_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) //ThreadedZEDGrab()/AcquireImages() grabbed images we haven't updated yet. + { + lock (zedCamera.grabLock) + { + zedCamera.RetrieveTextures(); //Tell the wrapper to compute the textures. + zedCamera.UpdateTextures(); //Tell the wrapper to update the textures. + imageTimeStamp = zedCamera.GetImagesTimeStamp(); + + } + + //For external module ... Trigger the capture done event. + if (OnGrab != null) + OnGrab(); + + //SVO and loop back ? --> reset position if needed + if (zedCamera.GetInputType() == sl.INPUT_TYPE.INPUT_TYPE_SVO && svoLoopBack) + { + int maxSVOFrame = zedCamera.GetSVONumberOfFrames(); + if (zedCamera.GetSVOPosition() >= maxSVOFrame - (svoRealTimeMode ? 2 : 1)) + { + zedCamera.SetSVOPosition(0); + if (enableTracking) + { + if (!(enableTracking = (zedCamera.ResetTracking(initialRotation, initialPosition) == sl.ERROR_CODE.SUCCESS))) + { + + Debug.LogError("ZED Tracking disabled: Not available during SVO playback when Loop is enabled."); + } + } + zedRigRoot.localPosition = initialPosition; + zedRigRoot.localRotation = initialRotation; + } + } + requestNewFrame = true; //Lets ThreadedZEDGrab/AcquireImages() start grabbing again. + newFrameAvailable = false; + } + } + + + /// + /// 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) //ZED inside-out tracking is enabled and initialized. + { + Quaternion r; + Vector3 v; + + isCameraTracked = true; + + if (UnityEngine.XR.XRDevice.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; + } + + arRig.ExtractLatencyPose(imageTimeStamp); //Find what HMD's pose was at ZED image's timestamp for latency compensation. + arRig.AdjustTrackingAR(zedPosition, zedOrientation, out r, out v, setIMUPriorInAR); + zedRigRoot.localRotation = r; + zedRigRoot.localPosition = v; + + ZEDSyncPosition = v; + ZEDSyncRotation = r; + HMDSyncPosition = arRig.LatencyPose().translation; + HMDSyncRotation = arRig.LatencyPose().rotation; + } + else //Not AR pass-through mode. + { + zedRigRoot.localRotation = zedOrientation; + if (!ZEDSupportFunctions.IsVector3NaN(zedPosition)) + zedRigRoot.localPosition = zedPosition; + } + } + else if (UnityEngine.XR.XRDevice.isPresent && isStereoRig) //ZED tracking is off but HMD tracking is on. Fall back to that. + { + isCameraTracked = true; + arRig.ExtractLatencyPose(imageTimeStamp); //Find what HMD's pose was at ZED image's timestamp for latency compensation. + zedRigRoot.localRotation = arRig.LatencyPose().rotation; + zedRigRoot.localPosition = arRig.LatencyPose().translation; + } + else //The ZED is not tracked by itself or an HMD. + isCameraTracked = false; + } + + /// + /// 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() + { + if (IsStereoRig && UnityEngine.XR.XRDevice.isPresent) + arRig.CollectPose(); //Save headset pose with current timestamp. + } + + /// + /// Updates images, collects HMD poses for latency correction, and applies tracking. + /// Called by Unity each frame. + /// + void Update() + { + + //Check if ZED is disconnected; invoke event and call function if so. + if (isDisconnected) + { + if (OnZEDDisconnected != null) + OnZEDDisconnected(); //Invoke event. Used for GUI message and pausing ZEDRenderingPlanes. + + ZEDDisconnected(); //Tries to reset the camera. + return; + } + + + // Then update all modules + 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. + UpdateMapping(); //Update mapping if activated + + + /// If in Unity Editor, update the ZEDManager status list +#if UNITY_EDITOR + //Update strings used for di splaying stats in the Inspector. + if (zedCamera != null) + { + float frame_drop_count = zedCamera.GetFrameDroppedPercent(); + float CurrentTickFPS = 1.0f / Time.deltaTime; + fps_engine = (fps_engine + CurrentTickFPS) / 2.0f; + engineFPS = fps_engine.ToString("F0") + " FPS"; + if (frame_drop_count > 30 && fps_engine < 45) + engineFPS += "WARNING: Low engine framerate detected"; + + if (isZEDTracked) + trackingState = ZEDTrackingState.ToString(); + else if (UnityEngine.XR.XRDevice.isPresent && isStereoRig) + trackingState = "HMD Tracking"; + else + trackingState = "Camera Not Tracked"; + } +#endif + + } + + public void LateUpdate() + { + if (IsStereoRig) + { + arRig.LateUpdateHmdRendering(); //Update textures on final AR rig for output to the headset. + } + } + #endregion + + /// + /// Event called when camera is disconnected + /// + void ZEDDisconnected() + { + cameraFPS = "Disconnected"; + isDisconnected = true; + + if (zedReady) + { + Reset(); //Cache tracking, turn it off and turn it back on again. + } + } + + private void OnDestroy() + { + //OnApplicationQuit(); + CloseManager(); + } + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////// SPATIAL MAPPING REGION ///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #region MAPPING_MODULE + /// + /// 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; + transform.rotation = Quaternion.identity; + + spatialMapping.StartStatialMapping(mappingResolutionPreset, mappingRangePreset, isMappingTextured); + } + + /// + /// 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() + { + if (spatialMapping != null) + { + if (saveMeshWhenOver) + SaveMesh(meshPath); + spatialMapping.StopStatialMapping(); + + } + } + + /// + /// Updates the filtering parameters and call the ZEDSpatialMapping instance's Update() function. + /// + private void UpdateMapping() + { + if (spatialMapping != null) + { + //if (IsMappingUpdateThreadRunning) + if (spatialMapping.IsRunning()) + { + spatialMapping.filterParameters = meshFilterParameters; + spatialMapping.Update(); + } + } + } + + /// + /// Toggles whether to display the mesh or not. + /// + /// True to make the mesh visible, false to make it invisible. + public void SwitchDisplayMeshState(bool state) + { + if (spatialMapping != null) + spatialMapping.SwitchDisplayMeshState(state); + } + + public void ClearAllMeshes() + { + if (spatialMapping != null) + spatialMapping.ClearAllMeshes(); + } + + /// + /// Pauses the current scan. + /// + /// True to pause the scanning, false to unpause it. + public void SwitchPauseState(bool state) + { + if (spatialMapping != null) + spatialMapping.SwitchPauseState(state); + } + + /// + /// 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 void SaveMesh(string meshPath = "ZEDMeshObj.obj") + { + spatialMapping.RequestSaveMesh(meshPath); + } + + /// + /// 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 = saveMeshWhenOver; + saveMeshWhenOver = false; + + gravityRotation = Quaternion.identity; + + spatialMapping.SetMeshRenderer(); + bool loadresult = spatialMapping.LoadMesh(meshPath); + + saveMeshWhenOver = oldSaveWhenOver; //Restoring old setting. + return loadresult; + } + #endregion + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////// AR REGION ////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #region AR_CAMERAS + /// + /// Stereo rig that adjusts images from ZED_Rig_Stereo to look correct in the HMD. + /// Hidden by default as it rarely needs to be changed. + /// + [HideInInspector] + public GameObject zedRigDisplayer; + private ZEDMixedRealityPlugin arRig; + /// + /// Create a GameObject to display the ZED in an headset (ZED-M Only). + /// + /// + private GameObject CreateZEDRigDisplayer() + { + //Make sure we don't already have one, such as if the camera disconnected and reconnected. + if (zedRigDisplayer != null) return zedRigDisplayer; + + zedRigDisplayer = new GameObject("ZEDRigDisplayer"); + arRig = zedRigDisplayer.AddComponent(); + + /*Screens left and right */ + GameObject leftScreen = GameObject.CreatePrimitive(PrimitiveType.Quad); + leftScreen.name = "Quad - Left"; + MeshRenderer meshLeftScreen = leftScreen.GetComponent(); + meshLeftScreen.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; + meshLeftScreen.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; + meshLeftScreen.receiveShadows = false; + meshLeftScreen.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + meshLeftScreen.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + meshLeftScreen.sharedMaterial = Resources.Load("Materials/Unlit/Mat_ZED_Unlit") as Material; + leftScreen.layer = arLayer; + GameObject.Destroy(leftScreen.GetComponent()); + + GameObject rightScreen = GameObject.CreatePrimitive(PrimitiveType.Quad); + rightScreen.name = "Quad - Right"; + MeshRenderer meshRightScreen = rightScreen.GetComponent(); + meshRightScreen.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; + meshRightScreen.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; + meshRightScreen.receiveShadows = false; + meshRightScreen.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; + meshRightScreen.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + GameObject.Destroy(rightScreen.GetComponent()); + meshRightScreen.sharedMaterial = Resources.Load("Materials/Unlit/Mat_ZED_Unlit") as Material; + rightScreen.layer = arLayer; + + /*Camera left and right*/ + 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. + camL.renderingPath = RenderingPath.Forward;//Minimal overhead + camL.clearFlags = CameraClearFlags.Color; + camL.backgroundColor = Color.black; + camL.cullingMask = 1 << arLayer; + camL.allowHDR = false; + camL.allowMSAA = false; + camL.depth = camLeftTransform.GetComponent().depth; + + GameObject camRight = new GameObject("cameraRight"); + camRight.transform.SetParent(zedRigDisplayer.transform); + Camera camR = camRight.AddComponent(); + 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. + camR.cullingMask = 1 << arLayer; + camR.allowHDR = false; + camR.allowMSAA = false; + camR.depth = camRightTransform.GetComponent().depth; + + HideFromWrongCameras.RegisterZEDCam(camL); + HideFromWrongCameras lhider = leftScreen.AddComponent(); + lhider.SetRenderCamera(camL); + lhider.showInNonZEDCameras = false; + + HideFromWrongCameras.RegisterZEDCam(camR); + HideFromWrongCameras rhider = rightScreen.AddComponent(); + rhider.SetRenderCamera(camR); + rhider.showInNonZEDCameras = false; + + SetLayerRecursively(camRight, arLayer); + SetLayerRecursively(camLeft, arLayer); + + //Hide camera in editor. +#if UNITY_EDITOR + if (!showarrig) + { + LayerMask layerNumberBinary = (1 << arLayer); //Convert layer index into binary number. + LayerMask flippedVisibleLayers = ~UnityEditor.Tools.visibleLayers; + UnityEditor.Tools.visibleLayers = ~(flippedVisibleLayers | layerNumberBinary); + } +#endif + leftScreen.transform.SetParent(zedRigDisplayer.transform); + rightScreen.transform.SetParent(zedRigDisplayer.transform); + + + arRig.finalCameraLeft = camLeft; + arRig.finalCameraRight = camRight; + arRig.ZEDEyeLeft = camLeftTransform.gameObject; + arRig.ZEDEyeRight = camRightTransform.gameObject; + arRig.quadLeft = leftScreen.transform; + arRig.quadRight = rightScreen.transform; + + + ZEDMixedRealityPlugin.OnHmdCalibChanged += CalibrationHasChanged; + if (UnityEngine.XR.XRDevice.isPresent) + HMDDevice = UnityEngine.XR.XRDevice.model; + + + return zedRigDisplayer; + } + + #endregion + + #region MIRROR + private ZEDMirror mirror = null; + private GameObject mirrorContainer = null; + void CreateMirror() + { + GameObject camLeft; + Camera camL; + if (mirrorContainer == null) + { + mirrorContainer = new GameObject("Mirror"); + mirrorContainer.hideFlags = HideFlags.HideInHierarchy; + + camLeft = new GameObject("MirrorCamera"); + camLeft.hideFlags = HideFlags.HideInHierarchy; + mirror = camLeft.AddComponent(); + mirror.manager = this; + camL = camLeft.AddComponent(); + } + else + { + camLeft = mirror.gameObject; + camL = camLeft.GetComponent(); + } + + camLeft.transform.parent = mirrorContainer.transform; + camL.stereoTargetEye = StereoTargetEyeMask.None; + camL.renderingPath = RenderingPath.Forward;//Minimal overhead + camL.clearFlags = CameraClearFlags.Color; + camL.backgroundColor = Color.black; + camL.cullingMask = 0; //It should see nothing. It gets its final image entirely from a Graphics.Blit call in ZEDMirror. + camL.allowHDR = false; + camL.allowMSAA = false; + camL.useOcclusionCulling = false; + + camL.depth = cameraLeft.GetComponent().depth; //Make sure it renders after the left cam so we can copy texture from latest frame. + } + #endregion + + /// + /// 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. + /// + public void Reset() + { + //Save tracking + if (enableTracking && isTrackingEnable) + { + zedCamera.GetPosition(ref zedOrientation, ref zedPosition); + } + + CloseManager(); + + openingLaunched = false; + running = false; + numberTriesOpening = 0; + forceCloseInit = false; + + Awake(); + + } + + + #region EventHandler + /// + /// Changes the real-world brightness by setting the brightness value in the shaders. + /// + /// New brightness value to be applied. Should be between 0 and 100. + public void SetCameraBrightness(int newVal) + { + SetFloatValueOnPlaneMaterials("_ZEDFactorAffectReal", newVal / 100f); + } + + /// + /// Sets the maximum depth range of real-world objects. Pixels further than this range are discarded. + /// + /// Furthest distance, in meters, that the camera will display pixels for. Should be between 0 and 20. + public void SetMaxDepthRange(float newVal) + { + if (newVal < 0 || newVal > 20) + { + Debug.LogWarning("Tried to set max depth range to " + newVal + "m. Must be within 0m and 20m."); + newVal = Mathf.Clamp(newVal, 0, 20); + } + SetFloatValueOnPlaneMaterials("_MaxDepth", newVal); + } + + /// + /// Sets a value of a float property on the material(s) rendering the ZED image. + /// Used to set things like brightness and maximum depth. + /// + /// Name of value/property within Shader. + /// New value for the specified property. + private void SetFloatValueOnPlaneMaterials(string propertyname, float newvalue) + { + foreach (ZEDRenderingPlane renderPlane in GetComponentsInChildren()) + { + Material rendmat; + if (renderPlane.ActualRenderingPath == RenderingPath.Forward) rendmat = renderPlane.canvas.GetComponent().material; + else if (renderPlane.ActualRenderingPath == RenderingPath.DeferredShading) rendmat = renderPlane.deferredMat; + else + { + Debug.LogError("Can't set " + propertyname + " value for Rendering Path " + renderPlane.ActualRenderingPath + + ": only Forward and DeferredShading are supported."); + return; + } + rendmat.SetFloat(propertyname, newvalue); + } + } + + + /// + /// 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; + } + #endregion + + + + +#if UNITY_EDITOR + /// + /// Handles changes to tracking or graphics settings changed from the Inspector. + /// + void OnValidate() + { + if (zedCamera != null) + { + // If tracking has been switched on + if (!isTrackingEnable && enableTracking) + { + //Enables tracking and initializes the first position of the camera. + if (!(enableTracking = (zedCamera.EnableTracking(ref zedOrientation, ref zedPosition, enableSpatialMemory, enablePoseSmoothing, estimateInitialPosition, pathSpatialMemory) == sl.ERROR_CODE.SUCCESS))) + { + isZEDTracked = false; + throw new Exception(ZEDLogMessage.Error2Str(ZEDLogMessage.ERROR.TRACKING_NOT_INITIALIZED)); + } + else + { + isZEDTracked = true; + isTrackingEnable = true; + } + } + + // If tracking has been switched off + if (isTrackingEnable && !enableTracking) + { + isZEDTracked = false; + lock (zedCamera.grabLock) + { + zedCamera.DisableTracking(); + } + isTrackingEnable = false; + } + + // If streaming has been switched on + if (enableStreaming && !isStreamingEnable) + { + lock (zedCamera.grabLock) + { + sl.ERROR_CODE err = zedCamera.EnableStreaming(streamingCodec, (uint)bitrate, (ushort)streamingPort, gopSize, adaptativeBitrate); + if (err == sl.ERROR_CODE.SUCCESS) + { + isStreamingEnable = true; + } + else + { + enableStreaming = false; + isStreamingEnable = false; + } + } + } + + // If streaming has been switched off + if (!enableStreaming && isStreamingEnable) + { + lock (zedCamera.grabLock) + { + zedCamera.DisableStreaming(); + isStreamingEnable = false; + } + } + + //Reapplies graphics settings based on current values. + setRenderingSettings(); + } + + } +#endif + + +} + diff --git a/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs.meta b/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs.meta new file mode 100644 index 0000000..320f7d9 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/ZEDManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 75b2a3ff7b847ca4490808f4c0432cd4 +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: -16100 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders.meta b/Assets/ZED/SDK/Helpers/Shaders.meta new file mode 100644 index 0000000..4744f5c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7773ac0a9781b2f448f6cd3665f273fb +folderAsset: yes +timeCreated: 1507708939 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/GUI.meta b/Assets/ZED/SDK/Helpers/Shaders/GUI.meta new file mode 100644 index 0000000..42a5c2e --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/GUI.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 288874ce02adce24abfdb0b686e07f9d +folderAsset: yes +timeCreated: 1507729382 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Default_OverlayNoZTest.shader b/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Default_OverlayNoZTest.shader new file mode 100644 index 0000000..522962c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Default_OverlayNoZTest.shader @@ -0,0 +1,93 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//UI to set in front of everything + Shader "ZED/ZED Default OverlayNoZTest" + { + Properties + { + [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} + _Color ("Tint", Color) = (1,1,1,1) + + _StencilComp ("Stencil Comparison", Float) = 8 + _Stencil ("Stencil ID", Float) = 0 + _StencilOp ("Stencil Operation", Float) = 0 + _StencilWriteMask ("Stencil Write Mask", Float) = 255 + _StencilReadMask ("Stencil Read Mask", Float) = 255 + + _ColorMask ("Color Mask", Float) = 15 + } + + SubShader + { + Tags + { + "Queue"="Overlay" + "IgnoreProjector"="True" + "RenderType"="Transparent" + "PreviewType"="Plane" + "CanUseSpriteAtlas"="True" + } + + Stencil + { + Ref [_Stencil] + Comp [_StencilComp] + Pass [_StencilOp] + ReadMask [_StencilReadMask] + WriteMask [_StencilWriteMask] + } + + Cull Off + Lighting Off + ZWrite Off + ZTest Off + Blend SrcAlpha OneMinusSrcAlpha + ColorMask [_ColorMask] + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + + struct appdata_t + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + half2 texcoord : TEXCOORD0; + }; + + fixed4 _Color; + fixed4 _TextureSampleAdd; //Added for font color support + + v2f vert(appdata_t IN) + { + v2f OUT; + OUT.vertex = UnityObjectToClipPos(IN.vertex); + OUT.texcoord = IN.texcoord; + #ifdef UNITY_HALF_TEXEL_OFFSET + OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1); + #endif + OUT.color = IN.color * _Color; + return OUT; + } + + sampler2D _MainTex; + + fixed4 frag(v2f IN) : SV_Target + { + half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color; //Added for font color support + clip (color.a - 0.01); + return color; + } + ENDCG + } + } + } \ No newline at end of file diff --git a/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Default_OverlayNoZTest.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Default_OverlayNoZTest.shader.meta new file mode 100644 index 0000000..a74df10 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Default_OverlayNoZTest.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5858f212fb4e7c64180b7d9a541fc41f +timeCreated: 1493218296 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Fade.shader b/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Fade.shader new file mode 100644 index 0000000..665dfd6 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Fade.shader @@ -0,0 +1,59 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//Fade system depending on the current alpha +Shader "ZED/ZED Fade" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + _FadeColor("Wire color", Color) = (1.0, 1.0, 1.0, 1.0) + + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 100 + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + float4 _FadeColor; + uniform float _Alpha; + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + // sample the texture + fixed4 col = tex2D(_MainTex, i.uv); + + return col*(1 - _Alpha) + (_Alpha)*_FadeColor; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Fade.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Fade.shader.meta new file mode 100644 index 0000000..e4c5a6d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/GUI/ZED_Fade.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 43bb64123ea14da43b05700aac6454e4 +timeCreated: 1497361402 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting.meta b/Assets/ZED/SDK/Helpers/Shaders/Lighting.meta new file mode 100644 index 0000000..e76f055 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 405478fdc64488842848a08a04f32b3d +folderAsset: yes +timeCreated: 1507709213 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred.shader b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred.shader new file mode 100644 index 0000000..677d76e --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred.shader @@ -0,0 +1,153 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//Set the depth/normals just after the depth texture is created +Shader "ZED/ZED Deferred" +{ +Properties + { + [HideInInspector] _MainTex("Base (RGB) Trans (A)", 2D) = "" {} + _DepthXYZTex("Depth texture", 2D) = "" {} + _CameraTex("Texture from ZED", 2D) = "" {} + _MaxDepth("Max Depth Range", Range(1,20)) = 20 + } + SubShader + { + + Pass + { + // Stencil is 2^8 bits, Unity uses 4 first bits + // 1 0 0 0 0 0 0 0 enables all lights + // 1 1 0 0 0 0 0 0 enables all except the light may be not rendered if too far way + // 1 1 1 0 0 0 0 0 enables all lights + + + + Stencil { + Ref 128 + Comp always + Pass replace + + } + + + ZWrite On + Cull Front + + CGPROGRAM + #pragma target 4.0 + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + #include "../ZED_Utils.cginc" + #include "Lighting.cginc" + #include "UnityCG.cginc" + #pragma multi_compile ___ UNITY_HDR_ON + #pragma multi_compile __ ZED_XYZ + #pragma multi_compile __ NO_DEPTH_OCC + struct v2f + { + float4 pos : POSITION; + float4 screenUV : TEXCOORD0; + float4 depthUV : TEXCOORD1; + + }; + sampler2D _MainTex; + float4 _MainTex_ST; + float4x4 _Model; + float4x4 _Projection; + sampler2D _DepthXYZTex; + float4 _DepthXYZTex_TexelSize; + float4 _DepthXYZTex_ST; + + v2f vert (v2f v) + { + v2f o; +#if SHADER_API_D3D11 + o.pos = float4(v.pos.x*2.0, v.pos.y*2.0, 0, 1); +#elif SHADER_API_GLCORE || SHADER_API_VULKAN + o.pos = float4(v.pos.x*2.0, -v.pos.y*2.0, 0, 1); + +#endif + o.screenUV = float4(v.pos.x - 0.5, v.pos.y - 0.5, 0, 1); + o.depthUV = float4(v.pos.x + 0.5f, v.pos.y + 0.5f, 0, 1); + return o; + + } + + sampler2D _MaskTex; + sampler2D _NormalsTex; + float _Exposure; + uniform int _ZEDReferenceMeasure; + uniform int ZEDGreenScreenActivated; + sampler2D ZEDMaskTexGreenScreen; + float _ZEDFactorAffectReal; + float _MaxDepth; + + void frag(v2f i, + out half4 outColor : SV_Target0, + out half4 outSpecRoughness : SV_Target1, + out half4 outNormal : SV_Target2, + out half4 outEmission : SV_Target3, + out float outDepth:DEPTH) + { + float2 uv = i.screenUV.xy / i.screenUV.w; +#if defined(ZED_XYZ) + float4 dxyz = tex2D (_DepthXYZTex, uv).xyzw; + + float d = computeDepthXYZ(dxyz.xyz); +#else + float4 dxyz = tex2D(_DepthXYZTex, i.depthUV).xxxx; + + //Filter out depth values beyond the max value. + if (_MaxDepth < 20.0) //Avoid clipping out FAR values when not using feature. + { + //if (dxyz.z > _MaxDepth) discard; + if (dxyz.z > _MaxDepth) discard; + } + + float d = computeDepthXYZ(dxyz.x); +#endif + + + + outSpecRoughness = half4(0,0,0,0); + + + float3 normals = tex2D(_NormalsTex, i.depthUV).rgb; + outColor = saturate(tex2D (_MainTex, i.depthUV).bgra); + outColor *= _ZEDFactorAffectReal; + + #ifdef NO_DEPTH_OCC + outDepth = 0; + #else + outDepth = saturate(d); + #endif + + + + if (ZEDGreenScreenActivated == 1) { + float a = (tex2D(ZEDMaskTexGreenScreen, float2(i.depthUV.x, 1 - i.depthUV.y)).a); + + a = a <= 0.5 ? 0 : 1; + + outDepth *= a; + } + #if UNITY_HDR_ON + outEmission = half4(0,0,0,0.5); + #else + outEmission = half4(1,1,1,0); + + #endif + outColor.a = 0; + + //Normal to world pos + normals.rgb = mul((float3x3)unity_CameraToWorld, float3(normals)).rgb; + normals = normalize(normals); + outNormal.rgb = normals*0.5 + 0.5; + + outNormal.w = 0.33; // Used as mask + } + ENDCG + } + } +} \ No newline at end of file diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred.shader.meta new file mode 100644 index 0000000..8c28be5 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9ed9dd24a1668264aa670d2bac004684 +timeCreated: 1490200926 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred_Lighting.shader b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred_Lighting.shader new file mode 100644 index 0000000..a5ddb1a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred_Lighting.shader @@ -0,0 +1,174 @@ +// Custom lighting effect on deferred +Shader "ZED/ZED Deferred Lighting" +{ +Properties { + _LightTexture0 ("", any) = "" {} + _LightTextureB0 ("", 2D) = "" {} + _ShadowMapTexture ("", any) = "" {} + _SrcBlend ("", Float) = 1 + _DstBlend ("", Float) = 1 +} +SubShader { + +// Pass 1: Lighting pass +// LDR case - Lighting encoded into a subtractive ARGB8 buffer +// HDR case - Lighting additively blended into floating point buffer +Pass { + ZWrite Off + Blend [_SrcBlend] [_DstBlend] + +CGPROGRAM +#pragma target 3.0 +#pragma vertex vert_deferred +#pragma fragment frag +#pragma multi_compile_lightpass +#pragma multi_compile ___ UNITY_HDR_ON + +#pragma exclude_renderers nomrt + +#include "UnityCG.cginc" +#include "UnityDeferredLibrary.cginc" +#include "UnityPBSLighting.cginc" +#include "UnityStandardUtils.cginc" +#include "UnityGBuffer.cginc" +#include "UnityStandardBRDF.cginc" + +sampler2D _CameraGBufferTexture0; +sampler2D _CameraGBufferTexture1; +sampler2D _CameraGBufferTexture2; + + +half Pow(half base, half exponent) { + return pow(max(0.0, base), exponent); +} + +half3 Pow3(half3 base, half exponent) { + return half3(Pow(base.x, exponent), Pow(base.y, exponent), Pow(base.z, exponent)); +} + +float4x4 _LightMatrixR; +float4x4 _LightMatrixG; +float4x4 _LightMatrixB; +float _ZEDExposure; +sampler2D _ZEDMap; +half3 EnvironmentalLightingDiffuse(half3 normal) { + + half4 h_normal; + h_normal.xyz = normal; + h_normal.w = 1; + half4 Mn_r = mul(_LightMatrixR, h_normal); + half4 Mn_g = mul(_LightMatrixG, h_normal); + half4 Mn_b = mul(_LightMatrixB, h_normal); + half3 color; + color.r = dot(Mn_r, h_normal); + color.g = dot(Mn_g, h_normal); + color.b = dot(Mn_b, h_normal); + return Pow3(_ZEDExposure * color, 0.454545); +} + +float _ZEDFactorAffectReal; +half4 CalculateLight (unity_v2f_deferred i) +{ + float3 wpos; + float2 uv; + float atten, fadeDist; + UnityLight light; + UNITY_INITIALIZE_OUTPUT(UnityLight, light); + UnityDeferredCalculateLightParams (i, wpos, uv, light.dir, atten, fadeDist); + + light.color = _LightColor.rgb * atten; + + half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv); + half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv); + half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv); + UnityStandardData data = UnityStandardDataFromGbuffer(gbuffer0, gbuffer1, gbuffer2); + int mask = gbuffer2.w * 3; // if mask equals 1, it's the ZED texture + #if defined(DIRECTIONAL) + if(mask == 1 ) return half4(data.diffuseColor*saturate(atten + log(1 + 1.72*length(UNITY_LIGHTMODEL_AMBIENT.rgb) / 4.0)), 1); + #endif + + float3 eyeVec = normalize(wpos-_WorldSpaceCameraPos); + half oneMinusReflectivity = 1 - SpecularStrength(data.specularColor.rgb); + + UnityIndirect ind; + UNITY_INITIALIZE_OUTPUT(UnityIndirect, ind); + //ind.diffuse = 0; + ind.specular = 0; + + half4 res = UNITY_BRDF_PBS(data.diffuseColor, data.specularColor, oneMinusReflectivity, data.smoothness, data.normalWorld, -eyeVec, light, ind); +#if defined(DIRECTIONAL) + if (mask != 1 && _ZEDExposure != -1) { + half3 d = dot(light.dir, data.normalWorld)*EnvironmentalLightingDiffuse(data.normalWorld); + res *= half4(d,1); + } +#endif + + return res; +} + +#ifdef UNITY_HDR_ON +half4 +#else +fixed4 +#endif +frag (unity_v2f_deferred i) : SV_Target +{ + half4 c = CalculateLight(i); + #ifdef UNITY_HDR_ON + return c; + #else + return exp2(-c); + #endif +} + +ENDCG +} + + +// Pass 2: Final decode pass. +// Used only with HDR off, to decode the logarithmic buffer into the main RT +Pass { + ZTest Always Cull Off ZWrite Off + Stencil { + ref [_StencilNonBackground] + readmask [_StencilNonBackground] + // Normally just comp would be sufficient, but there's a bug and only front face stencil state is set (case 583207) + compback equal + compfront equal + } + +CGPROGRAM +#pragma target 3.0 +#pragma vertex vert +#pragma fragment frag +#pragma exclude_renderers nomrt + +#include "UnityCG.cginc" + +sampler2D _LightBuffer; +struct v2f { + float4 vertex : SV_POSITION; + float2 texcoord : TEXCOORD0; +}; + +v2f vert (float4 vertex : POSITION, float2 texcoord : TEXCOORD0) +{ + v2f o; + o.vertex = UnityObjectToClipPos(vertex); + o.texcoord = texcoord.xy; +#ifdef UNITY_SINGLE_PASS_STEREO + o.texcoord = TransformStereoScreenSpaceTex(o.texcoord, 1.0f); +#endif + return o; +} + +fixed4 frag (v2f i) : SV_Target +{ + return -log2(tex2D(_LightBuffer, i.texcoord)); +} +ENDCG +} + +} +Fallback Off +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred_Lighting.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred_Lighting.shader.meta new file mode 100644 index 0000000..72d5b94 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Deferred_Lighting.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: fc101261ffd098d4182e59354a4e5e85 +timeCreated: 1490203094 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward.shader b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward.shader new file mode 100644 index 0000000..a72f7a9 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward.shader @@ -0,0 +1,111 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// Sets the ZED depth after the depth texture of Unity is created +Shader "ZED/ZED Forward" +{ + Properties + { + [HideInInspector] _MainTex("Base (RGB) Trans (A)", 2D) = "" {} + _DepthXYZTex("Depth texture", 2D) = "" {} + _CameraTex("Texture from ZED", 2D) = "" {} + } + + SubShader + { + + Stencil{ + Ref 129 + Comp[_ZEDStencilComp] + Pass keep + } + + + + Pass + { + + Tags { "RenderType"="Opaque" "Queue"="Geometry" "LightMode" = "Always" } + ZWrite On + ZTest Always + Cull Off + + CGPROGRAM + #pragma target 4.0 + #pragma vertex vert + #pragma fragment frag + #pragma exclude_renderers nomrt +#pragma multi_compile __ ZED_XYZ +#pragma multi_compile __ DEPTH_ALPHA +#pragma multi_compile __ NO_DEPTH + + #include "UnityCG.cginc" + #include "../ZED_Utils.cginc" + #include "Lighting.cginc" + #include "UnityCG.cginc" + float4 _MaskTex_ST; + struct v2f + { + float4 pos : SV_POSITION; + float4 screenUV : TEXCOORD0; + float4 depthUV : TEXCOORD1; + }; + v2f vert (float3 v : POSITION) + { + v2f o; + #if SHADER_API_D3D11 + o.pos = float4(v.x*2.0,v.y*2.0,0,1); +#elif SHADER_API_GLCORE + o.pos = float4(v.x*2.0, -v.y*2.0, 0, 1); +#else + o.pos = float4(v.x*2.0, v.y*2.0, 0, 1); +#endif + o.screenUV = float4(v.x-0.5,v.y-0.5,0,1); + o.depthUV = float4(v.x + 0.5, v.y + 0.5, 0, 1); + return o; + } + + sampler2D _MainTex; + sampler2D _DepthXYZTex; + uniform float4 _DepthXYZTex_TexelSize; + sampler2D ZEDMaskTexGreenScreen; + int ZEDGreenScreenActivated; + int ZED_GreenScreen_BG; + void frag(v2f i, + out half4 outColor : SV_Target0, + out float outDepth:SV_Depth) + { + float2 uv = i.screenUV.xy / i.screenUV.w; + float2 depthUV = i.depthUV.xy / i.depthUV.w; + float2 uvTex = float2(uv.x + 1.0f, uv.y + 1.0f); + uvTex.y = 1 - uvTex.y; + outColor = tex2D (_MainTex, uv).bgra; +#if defined(ZED_XYZ) + float4 dxyz = tex2D(_DepthXYZTex, depthUV).xyzw; + float realDepth = computeDepthXYZ(dxyz.rgb); +#else + float4 dxyz = tex2D(_DepthXYZTex, depthUV).xxxx; + float realDepth = computeDepthXYZ(dxyz.r); +#endif + + //For the green screen to apply a mask on depth +#if DEPTH_ALPHA + float a = (tex2D(ZEDMaskTexGreenScreen, uvTex).a); + + a = a <= 0.5 ? 0 : 1; + outDepth = realDepth*a; +#if NO_DEPTH + outDepth = 0; + +#endif + +#else + outDepth = realDepth; +#endif + + outColor = 0; + } + + ENDCG + } + } + +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward.shader.meta new file mode 100644 index 0000000..f44648d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4ab87418df3c64d4680282c62e272194 +timeCreated: 1489659460 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward_Lighting.shader b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward_Lighting.shader new file mode 100644 index 0000000..8e8945c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward_Lighting.shader @@ -0,0 +1,153 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + // Computes lighting and shadows and apply them to the real + Shader "ZED/ZED Forward Lighting" +{ + + Properties{ + [MaterialToggle] directionalLightEffect("Directional light affects image", Int) = 0 + _MaxDepth("Max Depth Range", Range(1,20)) = 20 + } + SubShader{ + + ZWrite On + Pass{ + Name "FORWARD" + Tags{ "LightMode" = "Always" } + + Cull Off + CGPROGRAM + // compile directives +#pragma target 4.0 + +#pragma vertex vert_surf +#pragma fragment frag_surf + + +#pragma multi_compile_fwdbase +#pragma multi_compile_fwdadd_fullshadows + +#pragma multi_compile __ NO_DEPTH_OCC + +#include "HLSLSupport.cginc" +#include "UnityShaderVariables.cginc" + +#define UNITY_PASS_FORWARDBASE +#include "UnityCG.cginc" + +#include "AutoLight.cginc" +#include "../ZED_Utils.cginc" +#define ZED_SPOT_LIGHT_DECLARATION +#define ZED_POINT_LIGHT_DECLARATION +#include "ZED_Lighting.cginc" + + sampler2D _MainTex; + + struct Input { + float2 uv_MainTex; + }; + + float4x4 _CameraMatrix; + sampler2D _DirectionalShadowMap; + + + struct v2f_surf { + float4 pos : SV_POSITION; + float4 pack0 : TEXCOORD0; + SHADOW_COORDS(4) + ZED_WORLD_DIR(1) + + }; + + + + float4 _MainTex_ST; + sampler2D _DepthXYZTex; + float4 _DepthXYZTex_ST; + sampler2D _MaskTex; + int _HasShadows; + float4 ZED_directionalLight[2]; + int directionalLightEffect; + float _ZEDFactorAffectReal; + float _MaxDepth; + + // vertex shader + v2f_surf vert_surf(appdata_full v) { + + + + v2f_surf o; + UNITY_INITIALIZE_OUTPUT(v2f_surf,o); + o.pos = UnityObjectToClipPos(v.vertex); + + ZED_TRANSFER_WORLD_DIR(o) + + o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex); + o.pack0.zw = TRANSFORM_TEX(v.texcoord, _DepthXYZTex); + + o.pack0.y = 1 - o.pack0.y; + o.pack0.w = 1 - o.pack0.w; + + TRANSFER_SHADOW(o); + + return o; + } + // fragment shader + void frag_surf(v2f_surf IN, out fixed4 outColor : SV_Target, out float outDepth : SV_Depth) { + UNITY_INITIALIZE_OUTPUT(fixed4,outColor); + float4 uv = IN.pack0; + + float3 zed_xyz = tex2D(_DepthXYZTex, uv.zw).xxx; + + //Filter out depth values beyond the max value. + if (_MaxDepth < 20.0) //Avoid clipping out FAR values when not using feature. + { + if (zed_xyz.z > _MaxDepth) discard; + } + + #ifdef NO_DEPTH_OCC + outDepth = 0; + #else + outDepth = computeDepthXYZ(zed_xyz.z); + #endif + + + fixed4 c = 0; + float4 color = tex2D(_MainTex, uv.xy).bgra; + float3 normals = tex2D(_NormalsTex, uv.zw).rgb; + + + //Apply directional light + color *= _ZEDFactorAffectReal; + + //Compute world space + float3 worldspace; + GET_XYZ(IN, zed_xyz.x, worldspace) + + //Apply shadows + // e(1) == 2.71828182846 + if (_HasShadows == 1) { + //Depends on the ambient lighting + float atten = saturate(tex2D(_DirectionalShadowMap, fixed2(uv.z, 1 - uv.w)) + log(1 + 1.72*length(UNITY_LIGHTMODEL_AMBIENT.rgb)/4.0)); + + c = half4(color*atten); + } + else { + c = half4(color); + } + + + //Add light + c += saturate(computeLighting(color.rgb, normals, worldspace, 1)); + + + c.a = 0; + outColor.rgb = c; + + } + + ENDCG + + } + } + Fallback Off +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward_Lighting.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward_Lighting.shader.meta new file mode 100644 index 0000000..813c8f4 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Forward_Lighting.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9a7011437ca03a24c8c5d45ccdf91e30 +timeCreated: 1485269531 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Hide.shader b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Hide.shader new file mode 100644 index 0000000..bb2385b --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Hide.shader @@ -0,0 +1,54 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//Invisble object to enable the shadows on CPU +Shader "ZED/ZED Hide" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType"="Opaque" } + + + Pass + { + ZWrite Off + ZTest Never + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata v) + { + v2f o; + o.vertex = -1; + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + return 0; + } + ENDCG + } + } + Fallback Off +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Hide.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Hide.shader.meta new file mode 100644 index 0000000..90af07e --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Hide.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9efc7125da4425d428044fc4c0d72ff7 +timeCreated: 1492502377 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Lighting.cginc b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Lighting.cginc new file mode 100644 index 0000000..e65ad13 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Lighting.cginc @@ -0,0 +1,164 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + + +#if !defined(ZED_LIGHTING) +#define ZED_LIGHTING + +#include "UnityCG.cginc" +#include "Lighting.cginc" +#include "UnityPBSLighting.cginc" + +#include "AutoLight.cginc" +/******************************************************************/ +/************** Point lights information **************************/ +/******************************************************************/ +struct ZED_PointLight{ + float4 color; + float range; + float3 position; +}; + + +/******************************************************************/ +/************** Spot lights information **************************/ +/******************************************************************/ +struct ZED_SpotLight{ + float4 color; + float3 position; + float4 direction; + float4 params;// angle, intensity, 1/range, cone interior +}; + +sampler2D _NormalsTex; +uniform float4 _CameraRotationQuat; + +#if defined(ZED_SPOT_LIGHT_DECLARATION) +StructuredBuffer spotLights; +int numberSpotLights; +#endif + +#if defined(ZED_POINT_LIGHT_DECLARATION) +StructuredBuffer pointLights; +int numberPointLights; +#endif +//FallOff the light +float FallOff(float dist, float inverseRange, float coeff) { + return lerp( 1.0, ( 1.0 - pow( dist * inverseRange * inverseRange, coeff ) ), 1 ); +} + +#define ZED_WORLD_DIR(index) float3 worldDirection : TEXCOORD##index; +#define ZED_TRANSFER_WORLD_DIR(o) o.worldDirection = mul(unity_ObjectToWorld, v.vertex).xyz - _WorldSpaceCameraPos; +#define GET_XYZ(o, z, world) world = (o.worldDirection/ o.pos.w) * z + _WorldSpaceCameraPos; + +float _Metallic; + +// Create a point light or spot light to be used per Unity +UnityLight CreateLight (float3 pos, float4 color, float3 worldPos, float3 normal) { + + UnityLight light; + light.dir = pos; + light.color = color; + light.ndotl = DotClamped(normal, light.dir); + + return light; +} + +//Compute the light for all light +#if defined(ZED_SPOT_LIGHT_DECLARATION) || defined(ZED_POINT_LIGHT_DECLARATION) +half4 computeLighting(float3 albedo, float3 normals, float3 worldPos, float alpha) { + fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos)); +#ifdef UNITY_COMPILER_HLSL + SurfaceOutputStandard o = (SurfaceOutputStandard)0; +#else + SurfaceOutputStandard o; +#endif + o.Albedo.rgb = albedo; + o.Emission = 0.0; + o.Alpha = 1.0; + o.Occlusion = 1.0; + o.Metallic = _Metallic; + o.Normal.rgb = mul((float3x3)unity_CameraToWorld, normals); + + float3 specularTint; + float oneMinusReflectivity; + o.Albedo.rgb = DiffuseAndSpecularFromMetallic( + albedo, o.Metallic, specularTint, oneMinusReflectivity + ); + float4 c = 0; + // Setup lighting environment + UnityGI gi; + UNITY_INITIALIZE_OUTPUT(UnityGI, gi); + gi.indirect.diffuse = 0; + gi.indirect.specular = 0; + + int indexPointLights = 0; + //For the point light +#if defined(ZED_POINT_LIGHT_DECLARATION) + UNITY_LOOP + for (indexPointLights = 0; indexPointLights < numberPointLights; indexPointLights++) { + float3 lightVec = pointLights[indexPointLights].position - worldPos; + + + if (pointLights[indexPointLights].range - length(lightVec) < 0) { + continue; + } + + float att = FallOff(dot(lightVec, lightVec), 1 / pointLights[indexPointLights].range, 0.2); + float v = dot(lightVec, float3(o.Normal.x, o.Normal.y, o.Normal.z)); + + + //Remove light from backward + //UNITY_BRANCH + if (dot(lightVec, float3(o.Normal.x, o.Normal.y, o.Normal.z)) <= 0.0) { + continue; + } + + UnityLight p = CreateLight(lightVec, pointLights[indexPointLights].color*att*alpha, worldPos, o.Normal.rgb); + + gi.light = p; + c += UNITY_BRDF_PBS(o.Albedo.rgb, specularTint, oneMinusReflectivity, 0, o.Normal.rgb, normalize(_WorldSpaceCameraPos - worldPos), p, gi.indirect); + c.a = 1.0; + } +#endif + c.a = 1.0; + + //For the spot light +#if defined(ZED_SPOT_LIGHT_DECLARATION) + int indexSpotLights = 0; + UNITY_LOOP + for (indexSpotLights = 0; indexSpotLights < numberSpotLights; indexSpotLights++) { + float3 lightVec = spotLights[indexSpotLights].position - worldPos; + float att = FallOff(dot(lightVec, lightVec), spotLights[indexSpotLights].params.z, 0.8); + + + float3 dirSpotToWorld = -lightVec; + float dotDirectionWorld = dot(normalize(dirSpotToWorld), spotLights[indexSpotLights].direction.xyz); + float angleWorld = degrees(acos(dotDirectionWorld)); + float angleMax = spotLights[indexSpotLights].params.x / 2.0; + + UNITY_BRANCH + if (dotDirectionWorld < 0 || dotDirectionWorld < spotLights[indexSpotLights].direction.w) { + continue; + + } + else { + float angleP = angleMax*(1 - spotLights[indexSpotLights].params.w); + UNITY_BRANCH + if (angleP < angleWorld && angleWorld < angleMax) { + att *= (angleMax - angleWorld) / (angleMax - angleP); + } + + } + att = saturate(att); + UnityLight p = CreateLight(lightVec, (spotLights[indexSpotLights].color)*att*alpha, worldPos, o.Normal.rgb); + + gi.light = p; + c += UNITY_BRDF_PBS(o.Albedo.rgb, specularTint, oneMinusReflectivity, 1, o.Normal.rgb, normalize(_WorldSpaceCameraPos - worldPos), p, gi.indirect); + c.a = 1.0; + } +#endif + return c; +} +#endif + +#endif \ No newline at end of file diff --git a/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Lighting.cginc.meta b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Lighting.cginc.meta new file mode 100644 index 0000000..fdef186 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Lighting/ZED_Lighting.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0ff764e76637d904593764201f980c5e +timeCreated: 1490181781 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection.meta b/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection.meta new file mode 100644 index 0000000..f3d9cbb --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f0fe2343cfe051e4faa114dee43f5281 +folderAsset: yes +timeCreated: 1543443412 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection/GeometryWirePlane.shader b/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection/GeometryWirePlane.shader new file mode 100644 index 0000000..318e2cc --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection/GeometryWirePlane.shader @@ -0,0 +1,121 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +/// +/// Basic wireframe shader with alpha color that can be used for rendering planes. +/// This will draw a mesh along with 0.5 transparency inside the vertices +/// +Shader "Custom/Plane Detection/ GeometryWirePlane" +{ + Properties + { + _WireColor("Wire color", Color) = (1.0, 1.0, 1.0, 1.0) + _WireThickness("Wire thickness", Range(0, 800)) = 100 + } + SubShader + { + Tags{ "RenderType" = "Opaque" } + + + + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + ZTest Always + CGPROGRAM +#pragma vertex vert +#pragma geometry geom +#pragma fragment frag + +#pragma target 5.0 +#pragma only_renderers d3d11 + +#include "UnityCG.cginc" + + float4 _WireColor; + float _WireThickness; + + // Based on approach described in Shader-Based Wireframe Drawing (2008) + // http://orbit.dtu.dk/en/publications/id(13e2122d-bec7-48de-beca-03ce6ea1c3f1).html + + struct v2g + { + float4 viewPos : SV_POSITION; + UNITY_VERTEX_OUTPUT_STEREO + }; + + v2g vert(appdata_base v) + { + UNITY_SETUP_INSTANCE_ID(v); + v2g o; + o.viewPos = UnityObjectToClipPos(v.vertex); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + return o; + } + + // inverseW is to counteract the effect of perspective-correct interpolation so that the lines + // look the same thickness regardless of their depth in the scene. + struct g2f + { + float4 viewPos : SV_POSITION; + float inverseW : TEXCOORD0; + float3 dist : TEXCOORD1; + UNITY_VERTEX_OUTPUT_STEREO + }; + + [maxvertexcount(3)] + void geom(triangle v2g i[3], inout TriangleStream triStream) + { + // Calculate the vectors that define the triangle from the input points. + float2 point0 = i[0].viewPos.xy / i[0].viewPos.w; + float2 point1 = i[1].viewPos.xy / i[1].viewPos.w; + float2 point2 = i[2].viewPos.xy / i[2].viewPos.w; + + // Calculate the area of the triangle. + float2 vector0 = point2 - point1; + float2 vector1 = point2 - point0; + float2 vector2 = point1 - point0; + float area = abs(vector1.x * vector2.y - vector1.y * vector2.x); + + float3 distScale[3]; + distScale[0] = float3(area / length(vector0), 0, 0); + distScale[1] = float3(0, area / length(vector1), 0); + distScale[2] = float3(0, 0, area / length(vector2)); + + float wireScale = 800 - _WireThickness; + + // Output each original vertex with its distance to the opposing line defined + // by the other two vertices. + g2f o; + + [unroll] + for (uint idx = 0; idx < 3; ++idx) + { + o.viewPos = i[idx].viewPos; + o.inverseW = 1.0 / o.viewPos.w; + o.dist = distScale[idx] * o.viewPos.w * wireScale; + UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i[idx], o); + triStream.Append(o); + } + } + + void frag(g2f i, out half4 outColor : SV_Target) + { + // Calculate minimum distance to one of the triangle lines, making sure to correct + // for perspective-correct interpolation. + float dist = min(i.dist[0], min(i.dist[1], i.dist[2])) * i.inverseW; + + // Make the intensity of the line very bright along the triangle edges but fall-off very + // quickly to go back to half transparency + float I = exp2(-2 * dist * dist / 10)+ 0.2; + + // Fade out the alpha but not the color so we don't get any weird halo effects from + // a fade to a different color. + float4 color = _WireColor; + color.a = I; + outColor = color; + } + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection/GeometryWirePlane.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection/GeometryWirePlane.shader.meta new file mode 100644 index 0000000..6399166 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PlaneDetection/GeometryWirePlane.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0a38398fb6c3e8e4f82320212680ec72 +timeCreated: 1521651078 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing.meta b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing.meta new file mode 100644 index 0000000..7aec025 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6242be9d6531fd04c9339feeb31c33f4 +folderAsset: yes +timeCreated: 1507709255 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blit.shader b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blit.shader new file mode 100644 index 0000000..de4f377 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blit.shader @@ -0,0 +1,55 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//Custom blit, to blit canal alpha to all canals +Shader "ZED/ZED Blit" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType"="Opaque" } + + //Blit Alpha to R + Pass + { + ZTest Always Cull Off ZWrite Off + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + fixed col = tex2D(_MainTex, i.uv).a; + return col; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blit.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blit.shader.meta new file mode 100644 index 0000000..aa5b4ed --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blit.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0e1a1e36ac2ada24ca19515d7e86836c +timeCreated: 1497516224 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blur.shader b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blur.shader new file mode 100644 index 0000000..61bd61e --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blur.shader @@ -0,0 +1,301 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//Blurs with predefined kernel and weights +Shader "ZED/ZED Blur" +{ + Properties + { + _MainTex("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType" = "Opaque" } + ZWrite Off + ZTest Always + Cull Off + + + //0 - Blur based on alpha + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 4.0 + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + float4 _MainTex_TexelSize; + uniform int horizontal; + + uniform float weights[5]; + uniform float offset[5]; + float4 frag(v2f vi) : SV_Target + { + + + + float2 uv = vi.uv; + float result = tex2D(_MainTex, uv).a * weights[0]; // current fragment's contribution + int i = 0; + if (horizontal == 1) + { + + result += tex2D(_MainTex, uv + float2(offset[1] * _MainTex_TexelSize.x, 0.0)).a * weights[1]; + result += tex2D(_MainTex, uv - float2(offset[1] * _MainTex_TexelSize.x, 0.0)).a * weights[1]; + + result += tex2D(_MainTex, uv + float2(offset[2] * _MainTex_TexelSize.x, 0.0)).a * weights[2]; + result += tex2D(_MainTex, uv - float2(offset[2] * _MainTex_TexelSize.x, 0.0)).a * weights[2]; + + + } + else + { + + result += tex2D(_MainTex, uv + float2(0.0, offset[1] * _MainTex_TexelSize.y)).a * weights[1]; + result += tex2D(_MainTex, uv - float2(0.0, offset[1] * _MainTex_TexelSize.y)).a * weights[1]; + + result += tex2D(_MainTex, uv + float2(0.0, offset[2] * _MainTex_TexelSize.y)).a * weights[2]; + result += tex2D(_MainTex, uv - float2(0.0, offset[2] * _MainTex_TexelSize.y)).a * weights[2]; + } + + return float4(tex2D(_MainTex, uv).rgb, result); + } + ENDCG + } + // 1 - Blur based on RGB, R unchanged, GB blured + Pass + { + CGPROGRAM +#pragma vertex vert +#pragma fragment frag +#pragma target 4.0 +#include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + float4 _MainTex_TexelSize; + uniform int horizontal; + + uniform float weights2[5]; + uniform float offset2[5]; + float4 frag(v2f vi) : SV_Target + { + + + + float2 uv = vi.uv; + float3 result = tex2D(_MainTex, uv).rgb * weights2[0]; // current fragment's contribution + result.r = tex2D(_MainTex, uv).r; + int i = 0; + if (horizontal == 1) + { + + result.gb += tex2D(_MainTex, uv + float2(offset2[1] * _MainTex_TexelSize.x, 0.0)).gb * weights2[1]; + result.gb += tex2D(_MainTex, uv - float2(offset2[1] * _MainTex_TexelSize.x, 0.0)).gb * weights2[1]; + + result.gb += tex2D(_MainTex, uv + float2(offset2[2] * _MainTex_TexelSize.x, 0.0)).gb * weights2[2]; + result.gb += tex2D(_MainTex, uv - float2(offset2[2] * _MainTex_TexelSize.x, 0.0)).gb * weights2[2]; + + } + else + { + + result.gb += tex2D(_MainTex, uv + float2(0.0, offset2[1] * _MainTex_TexelSize.y)).gb * weights2[1]; + result.gb += tex2D(_MainTex, uv - float2(0.0, offset2[1] * _MainTex_TexelSize.y)).gb * weights2[1]; + + result.gb += tex2D(_MainTex, uv + float2(0.0, offset2[2] * _MainTex_TexelSize.y)).gb * weights2[2]; + result.gb += tex2D(_MainTex, uv - float2(0.0, offset2[2] * _MainTex_TexelSize.y)).gb * weights2[2]; + + } + + return float4(result.x, result.y, result.z, 1); + } + ENDCG + } + + // 2 - Blur based with mask + Pass + { + CGPROGRAM +#pragma vertex vert +#pragma fragment frag +#pragma target 4.0 +#include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + sampler2D _Mask; + float4 _MainTex_ST; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + float4 _MainTex_TexelSize; + uniform int horizontal; + + uniform float weights[5]; + uniform float offset[5]; + float4 frag(v2f vi) : SV_Target + { + + + //TODO issue : The blur will shrink the virtual due to the mask + float2 uv = vi.uv; + float3 result = tex2D(_MainTex, uv).rgb; + if (tex2D(_Mask, uv).r != 0) { + result *= weights[0]; // current fragment's contribution + int i = 0; + if (horizontal == 1) + { + + result += tex2D(_MainTex, uv + float2(offset[1] * _MainTex_TexelSize.x, 0.0)).rgb * weights[1]; + result += tex2D(_MainTex, uv - float2(offset[1] * _MainTex_TexelSize.x, 0.0)).rgb * weights[1]; + + result += tex2D(_MainTex, uv + float2(offset[2] * _MainTex_TexelSize.x, 0.0)).rgb * weights[2]; + result += tex2D(_MainTex, uv - float2(offset[2] * _MainTex_TexelSize.x, 0.0)).rgb * weights[2]; + + } + else + { + + result += tex2D(_MainTex, uv + float2(0.0, offset[1] * _MainTex_TexelSize.y)).rgb * weights[1]; + result += tex2D(_MainTex, uv - float2(0.0, offset[1] * _MainTex_TexelSize.y)).rgb * weights[1]; + + result += tex2D(_MainTex, uv + float2(0.0, offset[2] * _MainTex_TexelSize.y)).rgb * weights[2]; + result += tex2D(_MainTex, uv - float2(0.0, offset[2] * _MainTex_TexelSize.y)).rgb * weights[2]; + + } + } + + return float4(result, 1); + } + ENDCG + } + + //3 - Blur based on R + Pass + { + CGPROGRAM +#pragma vertex vert +#pragma fragment frag +#pragma target 4.0 +#include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + float4 _MainTex_TexelSize; + uniform int horizontal; + + uniform float weights[5]; + uniform float offset[5]; + float4 frag(v2f vi) : SV_Target + { + + + + float2 uv = vi.uv; + float result = tex2D(_MainTex, uv).r * weights[0]; // current fragment's contribution + int i = 0; + if (horizontal == 1) + { + + result += tex2D(_MainTex, uv + float2(offset[1] * _MainTex_TexelSize.x, 0.0)).r * weights[1]; + result += tex2D(_MainTex, uv - float2(offset[1] * _MainTex_TexelSize.x, 0.0)).r * weights[1]; + + result += tex2D(_MainTex, uv + float2(offset[2] * _MainTex_TexelSize.x, 0.0)).r * weights[2]; + result += tex2D(_MainTex, uv - float2(offset[2] * _MainTex_TexelSize.x, 0.0)).r * weights[2]; + + } + else + { + + result += tex2D(_MainTex, uv + float2(0.0, offset[1] * _MainTex_TexelSize.y)).r * weights[1]; + result += tex2D(_MainTex, uv - float2(0.0, offset[1] * _MainTex_TexelSize.y)).r * weights[1]; + + result += tex2D(_MainTex, uv + float2(0.0, offset[2] * _MainTex_TexelSize.y)).r * weights[2]; + result += tex2D(_MainTex, uv - float2(0.0, offset[2] * _MainTex_TexelSize.y)).r * weights[2]; + + } + + return float4(result, result, result, result); + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blur.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blur.shader.meta new file mode 100644 index 0000000..0fec221 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Blur.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: ff7f942218f18e54d8ad8c85b234c74c +timeCreated: 1486117105 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_ComposeMask.shader b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_ComposeMask.shader new file mode 100644 index 0000000..f27d1d3 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_ComposeMask.shader @@ -0,0 +1,54 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//Composes a mask from the red canal and the alpha canal of another texture +Shader "ZED/ZED ComposeMask" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType"="Opaque" } + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + sampler2D _Mask; + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + fixed4 col = tex2D(_Mask, i.uv).r + (tex2D(_MainTex, i.uv).a); + + return col; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_ComposeMask.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_ComposeMask.shader.meta new file mode 100644 index 0000000..895babf --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_ComposeMask.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: cbcdddda683f5cd4fba55830221ff820 +timeCreated: 1504261869 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Post-Processing.shader b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Post-Processing.shader new file mode 100644 index 0000000..e142726 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Post-Processing.shader @@ -0,0 +1,105 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//Set noises and min black +Shader "ZED/ZED Post-Processing" { + Properties + { + _MainTex("Texture", 2D) = "white" {} + _MinBlack("Min black threshold", Range(0,1)) = 0.01 + } + SubShader + { + Tags{ "RenderType" = "Opaque" } + + ZWrite Off + ZTest Always + Cull Off + Pass + { + CGPROGRAM +#pragma vertex vert +#pragma fragment frag + +#include "UnityCG.cginc" +#pragma multi_compile ___ UNITY_HDR_ON + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + + uniform sampler2D _MainTex; + float4 _MainTex_ST; + float4 _MainTex_TexelSize; + sampler2D ZEDMaskPostProcess; + + uniform float _gamma; + uniform float _MinBlack; + uniform int _NoiseSize; + + + float rand(float2 co) { + return frac(sin(dot(co.xy, float2(12.9898, 78.233))) * 43758.5453); + } + + //Vertex Shader + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + + return o; + } + + //Fragment Shader + float4 frag(v2f i) : SV_Target{ + float2 invertUV = i.uv; + invertUV.y = 1 - i.uv.y; + float mask = tex2D(ZEDMaskPostProcess, i.uv); + + float4 zed = tex2D(_MainTex, i.uv); + + if (mask > 0.9f) + { + + //zed = (zed * 0.187) / (1.035 - zed); + float SqrtPixel = sqrt(zed.r * zed.r + zed.g * zed.g + zed.b * zed.b); + + float3 NoiseFactors = 2; + float2 random = _Time.x*_NoiseSize*floor(i.uv / _MainTex_TexelSize.xy / _NoiseSize) / 3.; + float3 NoiseValue = float3(rand(random), + rand(random), + rand(random)); + + float4 res = pow(zed, _gamma); + + + res.r += (NoiseFactors.r * NoiseValue.r - NoiseFactors.r * 0.5) / 255; + res.g += (NoiseFactors.g * NoiseValue.g - NoiseFactors.g * 0.5) / 255; + res.b += (NoiseFactors.b * NoiseValue.b - NoiseFactors.b * 0.5) / 255; + + //res = res / (res + 0.187) * 1.035; + res.a = 1.0f; + //res *= mask; +#if UNITY_COLORSPACE_GAMMA + return clamp(res, _MinBlack, 1.0f); +#else + return clamp(res, GammaToLinearSpaceExact(_MinBlack), 1.0f); +#endif + + } + return zed; + + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Post-Processing.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Post-Processing.shader.meta new file mode 100644 index 0000000..da82b35 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Post-Processing.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3a59afe186bbfc84281b438294e4f41a +timeCreated: 1491386243 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_StencilToMask.shader b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_StencilToMask.shader new file mode 100644 index 0000000..5f33007 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_StencilToMask.shader @@ -0,0 +1,54 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// Sets the stencil to a texture to be used as a mask +Shader "ZED/ZED StencilToMask" +{ + Properties + { + + } + SubShader + { + Tags { "RenderType"="Opaque" } + + + Pass + { + Stencil{ + Ref 148 + + Comp Equal + } + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + }; + + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + return float4(1,0,0,1); + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_StencilToMask.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_StencilToMask.shader.meta new file mode 100644 index 0000000..0adcc4a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_StencilToMask.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9c1bda7cee8bf92488dfaf7a2963af2b +timeCreated: 1504252689 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Surface_PostProcessing.shader b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Surface_PostProcessing.shader new file mode 100644 index 0000000..7d298e8 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Surface_PostProcessing.shader @@ -0,0 +1,58 @@ +// Upgrade NOTE: upgraded instancing buffer 'Props' to new syntax. + +//Example of surface shader using the stencil buffer for the post-processing +// Should be used in deferred only +Shader "ZED/ZED_Surface_PostProcessing" { + Properties { + _Color ("Color", Color) = (1,1,1,1) + _MainTex ("Albedo (RGB)", 2D) = "white" {} + _Glossiness ("Smoothness", Range(0,1)) = 0.5 + _Metallic ("Metallic", Range(0,1)) = 0.0 + } + SubShader { + Tags { "RenderType"="Opaque" } + LOD 200 + + //Used in deferred only for the post processing + Stencil{ + ref 148 + Pass replace + } + + CGPROGRAM + // Physically based Standard lighting model, and enable shadows on all light types + #pragma surface surf Standard fullforwardshadows + + // Use shader model 3.0 target, to get nicer looking lighting + #pragma target 3.0 + + sampler2D _MainTex; + + struct Input { + float2 uv_MainTex; + }; + + half _Glossiness; + half _Metallic; + fixed4 _Color; + + // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. + // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. + // #pragma instancing_options assumeuniformscaling + //UNITY_INSTANCING_BUFFER_START(Props) + // put more per-instance properties here + //UNITY_INSTANCING_BUFFER_END(Props) + + void surf (Input IN, inout SurfaceOutputStandard o) { + // Albedo comes from a texture tinted by color + fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; + o.Albedo = c.rgb; + // Metallic and smoothness come from slider variables + o.Metallic = _Metallic; + o.Smoothness = _Glossiness; + o.Alpha = c.a; + } + ENDCG + } + FallBack "Diffuse" +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Surface_PostProcessing.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Surface_PostProcessing.shader.meta new file mode 100644 index 0000000..5bf162c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Surface_PostProcessing.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f408df2c9d38f0a4788253fb1d9c106e +timeCreated: 1509374595 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Unlit_PostProcessing.shader b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Unlit_PostProcessing.shader new file mode 100644 index 0000000..f2bdcdb --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Unlit_PostProcessing.shader @@ -0,0 +1,68 @@ +//Example of Unlit using the stencil buffer for the post-processing +// Should be used in deferred only +Shader "ZED/ZED_Unlit_PostProcessing" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 100 + + //Used in deferred only for the post processing + Stencil{ + ref 148 + Pass replace + + } + + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + // make fog work + #pragma multi_compile_fog + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + UNITY_FOG_COORDS(1) + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + UNITY_TRANSFER_FOG(o,o.vertex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + // sample the texture + fixed4 col = tex2D(_MainTex, i.uv); + // apply fog + UNITY_APPLY_FOG(i.fogCoord, col); + return col; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Unlit_PostProcessing.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Unlit_PostProcessing.shader.meta new file mode 100644 index 0000000..8c1be3c --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/PostProcessing/ZED_Unlit_PostProcessing.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5efe839939b3d624b9bed96502a68c76 +timeCreated: 1509374435 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping.meta b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping.meta new file mode 100644 index 0000000..54682c0 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: de699a568c34d90449c5db7124f5eef7 +folderAsset: yes +timeCreated: 1509117821 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/GeometryWireframe.shader b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/GeometryWireframe.shader new file mode 100644 index 0000000..5e4e76b --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/GeometryWireframe.shader @@ -0,0 +1,120 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +/// +/// Basic wireframe shader that can be used for rendering spatial mapping meshes. +/// +Shader "Custom/Spatial Mapping/ GeometryWireframe" +{ + Properties + { + _WireColor("Wire color", Color) = (1.0, 1.0, 1.0, 1.0) + _WireThickness("Wire thickness", Range(0, 800)) = 100 + } + SubShader + { + Tags{ "RenderType" = "Opaque" } + + + + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + ZTest Always + CGPROGRAM +#pragma vertex vert +#pragma geometry geom +#pragma fragment frag + +#pragma target 5.0 +#pragma only_renderers d3d11 + +#include "UnityCG.cginc" + + float4 _WireColor; + float _WireThickness; + + // Based on approach described in Shader-Based Wireframe Drawing (2008) + // http://orbit.dtu.dk/en/publications/id(13e2122d-bec7-48de-beca-03ce6ea1c3f1).html + + struct v2g + { + float4 viewPos : SV_POSITION; + UNITY_VERTEX_OUTPUT_STEREO + }; + + v2g vert(appdata_base v) + { + UNITY_SETUP_INSTANCE_ID(v); + v2g o; + o.viewPos = UnityObjectToClipPos(v.vertex); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + return o; + } + + // inverseW is to counteract the effect of perspective-correct interpolation so that the lines + // look the same thickness regardless of their depth in the scene. + struct g2f + { + float4 viewPos : SV_POSITION; + float inverseW : TEXCOORD0; + float3 dist : TEXCOORD1; + UNITY_VERTEX_OUTPUT_STEREO + }; + + [maxvertexcount(3)] + void geom(triangle v2g i[3], inout TriangleStream triStream) + { + // Calculate the vectors that define the triangle from the input points. + float2 point0 = i[0].viewPos.xy / i[0].viewPos.w; + float2 point1 = i[1].viewPos.xy / i[1].viewPos.w; + float2 point2 = i[2].viewPos.xy / i[2].viewPos.w; + + // Calculate the area of the triangle. + float2 vector0 = point2 - point1; + float2 vector1 = point2 - point0; + float2 vector2 = point1 - point0; + float area = abs(vector1.x * vector2.y - vector1.y * vector2.x); + + float3 distScale[3]; + distScale[0] = float3(area / length(vector0), 0, 0); + distScale[1] = float3(0, area / length(vector1), 0); + distScale[2] = float3(0, 0, area / length(vector2)); + + float wireScale = 800 - _WireThickness; + + // Output each original vertex with its distance to the opposing line defined + // by the other two vertices. + g2f o; + + [unroll] + for (uint idx = 0; idx < 3; ++idx) + { + o.viewPos = i[idx].viewPos; + o.inverseW = 1.0 / o.viewPos.w; + o.dist = distScale[idx] * o.viewPos.w * wireScale; + UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(i[idx], o); + triStream.Append(o); + } + } + + void frag(g2f i, out half4 outColor : SV_Target) + { + // Calculate minimum distance to one of the triangle lines, making sure to correct + // for perspective-correct interpolation. + float dist = min(i.dist[0], min(i.dist[1], i.dist[2])) * i.inverseW; + + // Make the intensity of the line very bright along the triangle edges but fall-off very + // quickly. + float I = exp2(-2 * dist * dist / 10); + + // Fade out the alpha but not the color so we don't get any weird halo effects from + // a fade to a different color. + float4 color = I*_WireColor; + color.a = I; + outColor = color; + } + ENDCG + } + } + FallBack "Diffuse" +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/GeometryWireframe.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/GeometryWireframe.shader.meta new file mode 100644 index 0000000..b049dac --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/GeometryWireframe.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ff28f5e045891fc41ab0d0d9a402b51f +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Postprocess_blend.shader b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Postprocess_blend.shader new file mode 100644 index 0000000..12927bd --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Postprocess_blend.shader @@ -0,0 +1,80 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +/// +/// Blend the mesh to the ZED video +/// +Shader "Custom/Spatial Mapping/Postprocess Blend" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + _WireColor("Wire color", Color) = (1.0, 1.0, 1.0, 1.0) + } + SubShader + { + Tags { "RenderType"="Opaque" } + ZWrite Off + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + sampler2D _ZEDMeshTex; + float4 _ZEDMeshTex_ST; + float4 _MainTex_ST; + int _IsTextured; + float4 _WireColor; + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + + fixed4 frag(v2f i) : SV_Target + { + + float4 meshColor = tex2D(_ZEDMeshTex, i.uv); + + if (_IsTextured == 0) { + + if (length(meshColor) < 0.1) { + return tex2D(_MainTex, i.uv); + } + float4 m = clamp(tex2D(_MainTex, i.uv)*meshColor, float4(_WireColor.rgb - 0.05f,meshColor.a), float4(_WireColor.rgb + 0.05f, meshColor.a)); +#if !AWAY + m = tex2D(_MainTex, i.uv)*(1 - meshColor.a) + (meshColor.a)* float4(_WireColor.rgb - 0.05f, meshColor.a); +#endif + return m; + } + + + + if (meshColor.r != 0) { + return meshColor; + } + return tex2D(_MainTex, i.uv); + + } + + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Postprocess_blend.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Postprocess_blend.shader.meta new file mode 100644 index 0000000..8b2e074 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Postprocess_blend.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c5e2b5e6e2fe3274bbda6f48f9af188e +timeCreated: 1491402937 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Textures.shader b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Textures.shader new file mode 100644 index 0000000..91c7326 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Textures.shader @@ -0,0 +1,53 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +// Displays the texture generated by the mesh +Shader "Custom/Spatial Mapping/ Texture" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType"="Opaque" } + Cull Off + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + // sample the texture + fixed4 col = tex2D(_MainTex, i.uv); + return col.bgra; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Textures.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Textures.shader.meta new file mode 100644 index 0000000..e7332b6 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/Textures.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bde3233f98eca534c877a46041c3801f +timeCreated: 1490888761 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/WireframeVideoOverlay.shader b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/WireframeVideoOverlay.shader new file mode 100644 index 0000000..0e141e6 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/WireframeVideoOverlay.shader @@ -0,0 +1,65 @@ + +///======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +/// + /// Basic wireframe shader that can be used for rendering spatial mapping meshes. + /// + Shader "Custom/Spatial Mapping/ WireframeViedoOverlay" +{ + Properties + { + _WireColor("Wire color", Color) = (1.0, 1.0, 1.0, 1.0) + } + SubShader + { + Tags{ "RenderType" = "Opaque" } + Lighting Off + + + Pass + { + + CGPROGRAM + +#pragma vertex vert +#pragma fragment frag + +#include "UnityCG.cginc" + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + float dist : TEXCOORD1; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + float4 _WireColor; + v2f vert(appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + o.dist = length(ObjSpaceViewDir(v.vertex)); + return o; + } + + float4 frag(v2f i) : SV_Target + { + float4 color = _WireColor; + //#if AWAYS + color.a = 10 / (0.1 + i.dist*i.dist); + //#endif + return color; + } + ENDCG + } + } + Fallback off +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/WireframeVideoOverlay.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/WireframeVideoOverlay.shader.meta new file mode 100644 index 0000000..b4024e4 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/SpatialMapping/WireframeVideoOverlay.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 332ca72ae3411344e82dcf92913f57dd +timeCreated: 1501841098 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Unlit.meta b/Assets/ZED/SDK/Helpers/Shaders/Unlit.meta new file mode 100644 index 0000000..4bd7fa1 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Unlit.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 41f57bca42fe26a46bf976c957e04d7e +folderAsset: yes +timeCreated: 1508144269 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/Unlit/ZED_Unlit.shader b/Assets/ZED/SDK/Helpers/Shaders/Unlit/ZED_Unlit.shader new file mode 100644 index 0000000..4a39ed6 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Unlit/ZED_Unlit.shader @@ -0,0 +1,52 @@ +Shader "ZED/ZED_Unlit" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 100 + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + // sample the texture + fixed4 col = tex2D(_MainTex, i.uv); + return col; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/Unlit/ZED_Unlit.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/Unlit/ZED_Unlit.shader.meta new file mode 100644 index 0000000..4c6d53e --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/Unlit/ZED_Unlit.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e3ce76ae505317a40b8f52c2aac6fb9c +timeCreated: 1508144283 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/ZED_PointCloud.shader b/Assets/ZED/SDK/Helpers/Shaders/ZED_PointCloud.shader new file mode 100644 index 0000000..8c47198 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/ZED_PointCloud.shader @@ -0,0 +1,82 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +//Displays point cloud though geometry +Shader "ZED/ZED PointCloud" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + _Size("Size", Range(0.1,2)) = 0.1 + } + SubShader + { + + + Pass + { + Cull Off + CGPROGRAM + #pragma target 5.0 + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + + + struct PS_INPUT + { + float4 position : SV_POSITION; + float4 color : COLOR; + float3 normal : NORMAL; + + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + sampler2D _XYZTex; + sampler2D _ColorTex; + float4 _XYZTex_TexelSize; + float4x4 _Position; + + float _Size; + PS_INPUT vert (appdata_full v, uint vertex_id : SV_VertexID, uint instance_id : SV_InstanceID) + { + PS_INPUT o; + o.normal = v.normal; + + //Compute the UVS + float2 uv = float2( + clamp(fmod(instance_id, _XYZTex_TexelSize.z) * _XYZTex_TexelSize.x, _XYZTex_TexelSize.x, 1.0 - _XYZTex_TexelSize.x), + clamp(((instance_id -fmod(instance_id, _XYZTex_TexelSize.z) * _XYZTex_TexelSize.x) / _XYZTex_TexelSize.z) * _XYZTex_TexelSize.y, _XYZTex_TexelSize.y, 1.0 - _XYZTex_TexelSize.y) + ); + + + + + //Load the texture + float4 XYZPos = float4(tex2Dlod(_XYZTex, float4(uv, 0.0, 0.0)).rgb ,1.0f); + + //Set the World pos + o.position = mul(mul(UNITY_MATRIX_VP, _Position ), XYZPos); + + o.color = float4(tex2Dlod(_ColorTex, float4(uv, 0.0, 0.0)).bgr ,1.0f); + + return o; + } + + struct gs_out { + float4 position : SV_POSITION; + float4 color : COLOR; + }; + + + + fixed4 frag (PS_INPUT i) : SV_Target + { + return i.color; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Helpers/Shaders/ZED_PointCloud.shader.meta b/Assets/ZED/SDK/Helpers/Shaders/ZED_PointCloud.shader.meta new file mode 100644 index 0000000..47250de --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/ZED_PointCloud.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e559735f38c1ab04bb202a47093cfd4f +timeCreated: 1488185237 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Shaders/ZED_Utils.cginc b/Assets/ZED/SDK/Helpers/Shaders/ZED_Utils.cginc new file mode 100644 index 0000000..0f87aac --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/ZED_Utils.cginc @@ -0,0 +1,121 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +#if !defined(ZED_UTILS) +#define ZED_UTILS + + +#define MAX_DEPTH 0.9999f + + +#if UNITY_REVERSED_Z +#define NEAR_DEPTH MAX_DEPTH +#define FAR_DEPTH 1 - MAX_DEPTH +#else +#define NEAR_DEPTH 1 - MAX_DEPTH +#define FAR_DEPTH MAX_DEPTH +#endif + + +#define MAX_ZED_DEPTH 20 +#define MIN_ZED_DEPTH 0.1f + +#define ZED_CLAMP(name) name = clamp(name,MIN_ZED_DEPTH, MAX_ZED_DEPTH); + +#if UNITY_REVERSED_Z +#define ZED_DEPTH_CLAMP(name) clamp(name,FAR_DEPTH, NEAR_DEPTH) +#else +#define ZED_DEPTH_CLAMP(name) clamp(name,NEAR_DEPTH, FAR_DEPTH) +#endif + +#define ZED_PI 3.14159265359 +//Compute the depth of ZED to the Unity scale +float computeDepthXYZ(float3 colorXYZ) { + float d = FAR_DEPTH; + //Unity BUG, (isinf(colorXYZ.z) && colorXYZ.z > 0 and isinf(colorXYZ.z) && colorXYZ.z < 0 pass together, and it's not a nan + if (isinf(colorXYZ.z) && colorXYZ.z > 0) d = FAR_DEPTH; + if (isinf(colorXYZ.z) && colorXYZ.z < 0) d += NEAR_DEPTH; + if (d == FAR_DEPTH) return FAR_DEPTH; + else if (d == (FAR_DEPTH + NEAR_DEPTH)) return NEAR_DEPTH; + + colorXYZ = clamp(colorXYZ, 0.01, 20); + //reverse Y and Z axes + colorXYZ.b = -colorXYZ.b; +#if SHADER_API_D3D11 + colorXYZ.g = -colorXYZ.g; +#elif SHADER_API_GLCORE + colorXYZ.g = -colorXYZ.g * 2 + 1; +#endif + + float4 v = float4(colorXYZ, 1); + //Project to unity's coordinate + float4 depthXYZVector = mul(UNITY_MATRIX_P, v); + + if (depthXYZVector.w != depthXYZVector.w) return FAR_DEPTH; + + depthXYZVector.b /= (depthXYZVector.w); + float depthReal = depthXYZVector.b; + + return ZED_DEPTH_CLAMP(depthReal); +} + +float3 applyQuatToVec3(float4 q, float3 v) +{ + float3 t = 2 * cross(q.xyz, v); + return v + q.w * t + cross(q.xyz, t); +} + +//Compute the depth of ZED to the Unity scale +float computeDepthXYZ(float colorXYZ) { + + if (isinf(colorXYZ) && colorXYZ > 0) return FAR_DEPTH; + if (isinf(colorXYZ) && colorXYZ < 0) return NEAR_DEPTH; + + if (!isinf(colorXYZ) && !isfinite(colorXYZ)) return FAR_DEPTH; + //if (colorXYZ != colorXYZ) return FAR_DEPTH; //Doesn't correctly check for a NaN, and neither does isnan(). + colorXYZ = clamp(colorXYZ, 0.01, 20); + +#if SHADER_API_D3D11 + colorXYZ = -colorXYZ; +#elif SHADER_API_GLCORE + //colorXYZ = -colorXYZ * 2 + 1; + colorXYZ = -colorXYZ * 2; +#endif + + float4 v = float4(0,0, colorXYZ, 1); + //Project to unity's coordinate + float4 depthXYZVector = mul(UNITY_MATRIX_P, v); + + if (depthXYZVector.w != depthXYZVector.w) return FAR_DEPTH; + + depthXYZVector.b /= (depthXYZVector.w); + float depthReal = depthXYZVector.b; + + return ZED_DEPTH_CLAMP(depthReal); +} + +//Remove the optical center of the projection matrix for a specific object +float4 GetPosWithoutOpticalCenter(float4 vertex) { + float4x4 copy_projection = UNITY_MATRIX_P; + copy_projection[0][2] = 0; + copy_projection[1][2] = 0; + return mul(mul(mul(copy_projection, UNITY_MATRIX_V), UNITY_MATRIX_M), vertex); +} + +//Converts RGB to YUV +float3 RGBtoYUV(float3 rgb) +{ + float4x4 RGB2YUV = { 0.182586, 0.614231, 0.062007, 0.062745, + -0.100644, -0.338572, 0.439216, 0.501961, + 0.439216, -0.398942, -0.040274, 0.501961, + 0.000000, 0.000000, 0.000000, 1.000000 }; + + return mul(RGB2YUV, float4(rgb,1)).rgb; +} + +//Algorithm to compute the alpha of a frag depending of the similarity of a color. +//ColorCamera is the color from a texture given by the camera +float computeAlphaYUVFromYUV(float3 colorCamera, in float3 keyColor) { + return distance(keyColor.yz, colorCamera.yz); +} + +#endif diff --git a/Assets/ZED/SDK/Helpers/Shaders/ZED_Utils.cginc.meta b/Assets/ZED/SDK/Helpers/Shaders/ZED_Utils.cginc.meta new file mode 100644 index 0000000..b6c8fdd --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Shaders/ZED_Utils.cginc.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f5c0f53fe8a6fd34dac515b87d8802ff +timeCreated: 1485269531 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/NativeInterface.meta b/Assets/ZED/SDK/NativeInterface.meta new file mode 100644 index 0000000..bb54b0f --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 253817d0ef69fff4ebbc1d068c819629 +folderAsset: yes +timeCreated: 1507557757 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs b/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs new file mode 100644 index 0000000..deb1b1a --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs @@ -0,0 +1,2459 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using UnityEngine; +using System.Collections.Generic; +using System; +using System.Runtime.InteropServices; + + +namespace sl +{ + /// + /// 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. + /// + 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 + } + + /// + /// 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, used for extern calls to the wrapper. + /// + const string nameDll = sl.ZEDCommon.NameDLL; + + /// + /// 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. Used for destroying all textures when the camera closes. + /// + private List texturesRequested; + + /// + /// Width of the textures in pixels. Corresponds to the ZED's current resolution setting. + /// + private int imageWidth; + /// + /// 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; + /// + /// 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; + } + } + + + /// + /// True if the ZED SDK is installed. + /// + private static bool pluginIsReady = true; + + /// + /// Mutex for the image acquisition thread. + /// + public object grabLock = new object(); + + /// + /// Current ZED resolution setting. Set at initialization. + /// + private RESOLUTION currentResolution; + + /// + /// Callback for c++ debugging. Should not be used in C#. + /// + private delegate void DebugCallback(string message); + + /// + /// 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 ZEDCameraSettings cameraSettingsManager = new ZEDCameraSettings(); + + /// + /// 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; } + } + /// + /// ZED's current horizontal field of view in degrees. + /// + private float fov_H = 0.0f; + /// + /// 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; } + } + /// + /// ZED's current vertical field of view in degrees. + /// + public float VerticalFieldOfView + { + get { return fov_V; } + } + /// + /// 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 - ZED or ZED Mini. + /// + private sl.MODEL cameraModel; + + /// + /// Whether the camera has been successfully initialized. + /// + private bool cameraReady = false; + + /// + /// Stereo parameters for current ZED camera prior to rectification (distorted). + /// + public CalibrationParameters CalibrationParametersRaw + { + get { return calibrationParametersRaw; } + } + /// + /// Stereo parameters for current ZED camera after rectification (undistorted). + /// + public CalibrationParameters CalibrationParametersRectified + { + get { return calibrationParametersRectified; } + } + /// + /// Camera model - ZED or ZED Mini. + /// + public sl.MODEL CameraModel + { + get { return cameraModel; } + } + /// + /// 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; } + } + /// + /// List of DLLs needed to run the plugin. + /// + static private string[] dependenciesNeeded = + { + "sl_zed64.dll", + "sl_core64.dll", + "sl_input64.dll" + }; + + /// + /// Layer that only the ZED is able to see. Used in ZEDSteamVRControllerManager for 'clone' controllers. + /// + const int tagZEDCamera = 20; + + /// + /// Camera ID (for multiple cameras) + /// + public int CameraID= 0; + /// + /// Layer that only the ZED is able to see. Used in ZEDSteamVRControllerManager for 'clone' controllers. + /// + public static int Tag + { + get { return tagZEDCamera; } + } + /// + /// Layer that the ZED can't see, but overlay cameras created by ZEDMeshRenderer and ZEDPlaneRenderer can. + /// + int tagOneObject = 12; + /// + /// Layer that the ZED can't see, but overlay cameras created by ZEDMeshRenderer and ZEDPlaneRenderer can. + /// + public int TagOneObject + { + get { return tagOneObject; } + } + + + #region DLL Calls + /// + /// Current Plugin Version. + /// + public static readonly System.Version PluginVersion = new System.Version(2, 8, 0); + + + /******** DLL members ***********/ + [DllImport(nameDll, EntryPoint = "GetRenderEventFunc")] + private static extern IntPtr GetRenderEventFunc(); + + [DllImport(nameDll, EntryPoint = "dllz_register_callback_debuger")] + private static extern void dllz_register_callback_debuger(DebugCallback callback); + + + /* + * Utils function. + */ + + [DllImport(nameDll, EntryPoint = "dllz_unload_all_instances")] + private static extern void dllz_unload_all_instances(); + + [DllImport(nameDll, EntryPoint = "dllz_unload_instance")] + private static extern void dllz_unload_instance(int id); + + [DllImport(nameDll, EntryPoint = "dllz_find_usb_device")] + private static extern bool dllz_find_usb_device(USB_DEVICE dev); + + /* + * Create functions + */ + [DllImport(nameDll, EntryPoint = "dllz_create_camera")] + private static extern bool dllz_create_camera(int cameraID,bool verbose); + + + /* + * Opening function (Opens camera and creates textures). + */ + [DllImport(nameDll, EntryPoint = "dllz_open")] + private static extern int dllz_open(int cameraID,ref dll_initParameters parameters, System.Text.StringBuilder svoPath, System.Text.StringBuilder ipStream,int portStream,System.Text.StringBuilder output,System.Text.StringBuilder opt_settings_path); + + + + + /* + * Close function. + */ + [DllImport(nameDll, EntryPoint = "dllz_close")] + private static extern void dllz_close(int cameraID); + + + /* + * Grab function. + */ + [DllImport(nameDll, EntryPoint = "dllz_grab")] + private static extern int dllz_grab(int cameraID, ref sl.RuntimeParameters runtimeParameters); + + + + /* + * Recording functions. + */ + [DllImport(nameDll, EntryPoint = "dllz_enable_recording")] + private static extern int dllz_enable_recording(int cameraID,byte[] video_filename, int compresssionMode); + + [DllImport(nameDll, EntryPoint = "dllz_record")] + private static extern void dllz_record(int cameraID,ref Recording_state state); + + [DllImport(nameDll, EntryPoint = "dllz_disable_recording")] + private static extern bool dllz_disable_recording(int cameraID); + + + /* + * Texturing functions. + */ + [DllImport(nameDll, EntryPoint = "dllz_retrieve_textures")] + private static extern void dllz_retrieve_textures(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_updated_textures_timestamp")] + private static extern ulong dllz_get_updated_textures_timestamp(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_swap_textures")] + private static extern ulong dllz_swap_textures(int cameraID); + + + + [DllImport(nameDll, EntryPoint = "dllz_register_texture_image_type")] + private static extern int dllz_register_texture_image_type(int cameraID,int option, IntPtr id, Resolution resolution); + + [DllImport(nameDll, EntryPoint = "dllz_register_texture_measure_type")] + private static extern int dllz_register_texture_measure_type(int cameraID,int option, IntPtr id, Resolution resolution); + + [DllImport(nameDll, EntryPoint = "dllz_unregister_texture_measure_type")] + private static extern int dllz_unregister_texture_measure_type(int cameraID,int option); + + [DllImport(nameDll, EntryPoint = "dllz_unregister_texture_image_type")] + private static extern int dllz_unregister_texture_image_type(int cameraID,int option); + + [DllImport(nameDll, EntryPoint = "dllz_get_copy_mat_texture_image_type")] + private static extern IntPtr dllz_get_copy_mat_texture_image_type(int cameraID,int option); + + [DllImport(nameDll, EntryPoint = "dllz_get_copy_mat_texture_measure_type")] + private static extern IntPtr dllz_get_copy_mat_texture_measure_type(int cameraID,int option); + + /* + * Self-calibration functions. + */ + [DllImport(nameDll, EntryPoint = "dllz_reset_self_calibration")] + private static extern void dllz_reset_self_calibration(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_self_calibration_state")] + private static extern int dllz_get_self_calibration_state(int cameraID); + + + /* + * Camera control functions. + */ + + [DllImport(nameDll, EntryPoint = "dllz_get_input_type")] + private static extern int dllz_get_input_type(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_set_camera_fps")] + private static extern void dllz_set_camera_fps(int cameraID,int fps); + + [DllImport(nameDll, EntryPoint = "dllz_get_camera_fps")] + private static extern float dllz_get_camera_fps(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_width")] + private static extern int dllz_get_width(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_height")] + private static extern int dllz_get_height(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_calibration_parameters")] + private static extern IntPtr dllz_get_calibration_parameters(int cameraID,bool raw); + + [DllImport(nameDll, EntryPoint = "dllz_get_camera_model")] + private static extern int dllz_get_camera_model(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_zed_firmware")] + private static extern int dllz_get_zed_firmware(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_zed_serial")] + private static extern int dllz_get_zed_serial(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_camera_imu_transform")] + private static extern void dllz_get_camera_imu_transform(int cameraID,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(); + + [DllImport(nameDll, EntryPoint = "dllz_get_camera_timestamp")] + private static extern ulong dllz_get_camera_timestamp(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_current_timestamp")] + private static extern ulong dllz_get_current_timestamp(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_image_updater_time_stamp")] + private static extern ulong dllz_get_image_updater_time_stamp(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_frame_dropped_count")] + private static extern uint dllz_get_frame_dropped_count(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_frame_dropped_percent")] + private static extern float dllz_get_frame_dropped_percent(int cameraID); + + /* + * SVO control functions. + */ + + [DllImport(nameDll, EntryPoint = "dllz_set_svo_position")] + private static extern void dllz_set_svo_position(int cameraID,int frame); + + [DllImport(nameDll, EntryPoint = "dllz_get_svo_number_of_frames")] + private static extern int dllz_get_svo_number_of_frames(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_svo_position")] + private static extern int dllz_get_svo_position(int cameraID); + + + /* + * Depth Sensing utils functions. + */ + [DllImport(nameDll, EntryPoint = "dllz_set_confidence_threshold")] + private static extern void dllz_set_confidence_threshold(int cameraID,int threshold); + + [DllImport(nameDll, EntryPoint = "dllz_get_confidence_threshold")] + private static extern int dllz_get_confidence_threshold(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_set_depth_max_range_value")] + private static extern void dllz_set_depth_max_range_value(int cameraID,float distanceMax); + + [DllImport(nameDll, EntryPoint = "dllz_get_depth_max_range_value")] + private static extern float dllz_get_depth_max_range_value(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_depth_value")] + private static extern float dllz_get_depth_value(int cameraID,uint x, uint y); + + [DllImport(nameDll, EntryPoint = "dllz_get_distance_value")] + private static extern float dllz_get_distance_value(int cameraID,uint x, uint y); + + [DllImport(nameDll, EntryPoint = "dllz_get_normal_value")] + private static extern int dllz_get_normal_value(int cameraID,uint x, uint y, out Vector4 value); + + [DllImport(nameDll, EntryPoint = "dllz_get_xyz_value")] + private static extern int dllz_get_xyz_value(int cameraID,uint x, uint y, out Vector4 value); + + [DllImport(nameDll, EntryPoint = "dllz_get_depth_min_range_value")] + private static extern float dllz_get_depth_min_range_value(int cameraID); + + + /* + * Motion Tracking functions. + */ + [DllImport(nameDll, EntryPoint = "dllz_enable_tracking")] + private static extern int dllz_enable_tracking(int cameraID,ref Quaternion quat, ref Vector3 vec, bool enableSpatialMemory = false,bool enablePoseSmoothing = false,bool enableFloorAlignment = false, System.Text.StringBuilder aeraFilePath = null); + + [DllImport(nameDll, EntryPoint = "dllz_disable_tracking")] + private static extern void dllz_disable_tracking(int cameraID,System.Text.StringBuilder path); + + [DllImport(nameDll, EntryPoint = "dllz_save_current_area")] + private static extern int dllz_save_current_area(int cameraID,System.Text.StringBuilder path); + + [DllImport(nameDll, EntryPoint = "dllz_get_position_data")] + private static extern int dllz_get_position_data(int cameraID,ref Pose pose, int reference_frame); + + [DllImport(nameDll, EntryPoint = "dllz_get_position")] + private static extern int dllz_get_position(int cameraID,ref Quaternion quat, ref Vector3 vec, int reference_frame); + + [DllImport(nameDll, EntryPoint = "dllz_get_position_at_target_frame")] + private static extern int dllz_get_position_at_target_frame(int cameraID,ref Quaternion quaternion, ref Vector3 translation, ref Quaternion targetQuaternion, ref Vector3 targetTranslation, int reference_frame); + + [DllImport(nameDll, EntryPoint = "dllz_transform_pose")] + private static extern void dllz_transform_pose(ref Quaternion quaternion, ref Vector3 translation, ref Quaternion targetQuaternion, ref Vector3 targetTranslation); + + [DllImport(nameDll, EntryPoint = "dllz_reset_tracking")] + private static extern int dllz_reset_tracking(int cameraID,Quaternion rotation, Vector3 translation); + + [DllImport(nameDll, EntryPoint = "dllz_reset_tracking_with_offset")] + private static extern int dllz_reset_tracking_with_offset(int cameraID,Quaternion rotation, Vector3 translation, Quaternion offsetQuaternion, Vector3 offsetTranslation); + + [DllImport(nameDll, EntryPoint = "dllz_estimate_initial_position")] + private static extern int dllz_estimate_initial_position(int cameraID,ref Quaternion quaternion, ref Vector3 translation,int countSuccess, int countTimeout); + + [DllImport(nameDll, EntryPoint = "dllz_set_imu_prior_orientation")] + private static extern int dllz_set_imu_prior_orientation(int cameraID,Quaternion rotation); + + [DllImport(nameDll, EntryPoint = "dllz_get_internal_imu_orientation")] + private static extern int dllz_get_internal_imu_orientation(int cameraID,ref Quaternion rotation, int reference_time); + + [DllImport(nameDll, EntryPoint = "dllz_get_internal_imu_data")] + private static extern int dllz_get_internal_imu_data(int cameraID,ref IMUData imuData, int reference_time); + + [DllImport(nameDll, EntryPoint = "dllz_get_area_export_state")] + private static extern int dllz_get_area_export_state(int cameraID); + + /* + * Spatial Mapping functions. + */ + [DllImport(nameDll, EntryPoint = "dllz_enable_spatial_mapping")] + private static extern int dllz_enable_spatial_mapping(int cameraID,float resolution_meter, float max_range_meter, int saveTexture); + + [DllImport(nameDll, EntryPoint = "dllz_disable_spatial_mapping")] + private static extern void dllz_disable_spatial_mapping(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_pause_spatial_mapping")] + private static extern void dllz_pause_spatial_mapping(int cameraID,bool status); + + [DllImport(nameDll, EntryPoint = "dllz_request_mesh_async")] + private static extern void dllz_request_mesh_async(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_get_mesh_request_status_async")] + private static extern int dllz_get_mesh_request_status_async(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_update_mesh")] + private static extern int dllz_update_mesh(int cameraID,int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmesh); + + [DllImport(nameDll, EntryPoint = "dllz_retrieve_mesh")] + private static extern int dllz_retrieve_mesh(int cameraID,Vector3[] vertices, int[] triangles, int nbSubmesh, Vector2[] uvs, IntPtr textures); + + [DllImport(nameDll, EntryPoint = "dllz_save_mesh")] + private static extern bool dllz_save_mesh(int cameraID,string filename, MESH_FILE_FORMAT format); + + [DllImport(nameDll, EntryPoint = "dllz_load_mesh")] + private static extern bool dllz_load_mesh(int cameraID,string filename, int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbMaxSubmesh, int[] textureSize = null); + + [DllImport(nameDll, EntryPoint = "dllz_apply_texture")] + private static extern bool dllz_apply_texture(int cameraID,int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int[] textureSize, int nbSubmesh); + + [DllImport(nameDll, EntryPoint = "dllz_filter_mesh")] + private static extern bool dllz_filter_mesh(int cameraID,FILTER meshFilter, int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmesh); + + [DllImport(nameDll, EntryPoint = "dllz_get_spatial_mapping_state")] + private static extern int dllz_get_spatial_mapping_state(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_spatial_mapping_merge_chunks")] + private static extern void dllz_spatial_mapping_merge_chunks(int cameraID,int numberFaces, int[] nbVerticesInSubemeshes, int[] nbTrianglesInSubemeshes, ref int nbSubmeshes, int[] updatedIndices, ref int nbVertices, ref int nbTriangles, int nbSubmesh); + + [DllImport(nameDll, EntryPoint = "dllz_spatial_mapping_get_gravity_estimation")] + private static extern void dllz_spatial_mapping_get_gravity_estimation(int cameraID,ref Vector3 v); + + /* + * Plane Detection functions (starting v2.4) + */ + [DllImport(nameDll, EntryPoint = "dllz_find_floor_plane")] + private static extern IntPtr dllz_find_floor_plane(int cameraID,out Quaternion rotation,out Vector3 translation, Vector3 priorQuaternion, Vector3 priorTranslation); + + [DllImport(nameDll, EntryPoint = "dllz_find_plane_at_hit")] + private static extern IntPtr dllz_find_plane_at_hit(int cameraID,Vector2 HitPixel,bool refine); + + [DllImport(nameDll, EntryPoint = "dllz_convert_floorplane_to_mesh")] + private static extern int dllz_convert_floorplane_to_mesh(int cameraID,Vector3[] vertices, int[] triangles,out int numVertices,out int numTriangles); + + [DllImport(nameDll, EntryPoint = "dllz_convert_hitplane_to_mesh")] + private static extern int dllz_convert_hitplane_to_mesh (int cameraID,Vector3[] vertices, int[] triangles, out int numVertices, out int numTriangles); + + + /* + * Streaming Module functions (starting v2.8) + */ + [DllImport(nameDll, EntryPoint = "dllz_enable_streaming")] + private static extern int dllz_enable_streaming(int cameraID, sl.STREAMING_CODEC codec, uint bitrate, ushort port, int gopSize, int adaptativeBitrate); + + [DllImport(nameDll, EntryPoint = "dllz_is_streaming_enabled")] + private static extern int dllz_is_streaming_enabled(int cameraID); + + [DllImport(nameDll, EntryPoint = "dllz_disable_streaming")] + private static extern void dllz_disable_streaming(int cameraID); + + + /* + * Specific plugin functions + */ + [DllImport(nameDll, EntryPoint = "dllz_check_plugin")] + private static extern int dllz_check_plugin(int major, int minor); + + [DllImport(nameDll, EntryPoint = "dllz_get_sdk_version")] + private static extern IntPtr dllz_get_sdk_version(); + + [DllImport(nameDll, EntryPoint = "dllz_compute_offset")] + private static extern void dllz_compute_offset(float[] A, float[] B, int nbVectors, float[] C); + + [DllImport(nameDll, EntryPoint = "dllz_compute_optical_center_offsets")] + private static extern System.IntPtr dllz_compute_optical_center_offsets(ref Vector4 calibLeft, ref Vector4 calibRight, sl.Resolution imageResolution, float planeDistance); + + + /* + * Retreieves used by mat + */ + [DllImport(nameDll, EntryPoint = "dllz_retrieve_measure")] + private static extern int dllz_retrieve_measure(int cameraID,System.IntPtr ptr, int type, int mem, sl.Resolution resolution); + + [DllImport(nameDll, EntryPoint = "dllz_retrieve_image")] + private static extern int dllz_retrieve_image(int cameraID,System.IntPtr ptr, int type, int mem, sl.Resolution resolution); + + #endregion + + public static void UnloadPlugin() + { + dllz_unload_all_instances (); + } + + public static void UnloadInstance(int id) + { + dllz_unload_instance (id); + } + + + public static void ComputeOffset(float[] A, float[] B, int nbVectors, ref Quaternion rotation, ref Vector3 translation) + { + float[] C = new float[16]; + if (A.Length != 4 * nbVectors || B.Length != 4 * nbVectors || C.Length != 16) return; + dllz_compute_offset(A, B, nbVectors, C); + + Matrix4x4 m = Matrix4x4.identity; + Float2Matrix(ref m, C); + + rotation = Matrix4ToQuaternion(m); + Vector4 t = m.GetColumn(3); + translation.x = t.x; + translation.y = t.y; + translation.z = t.z; + + } + + /// + /// Return a string from a pointer to a char. Used in GetSDKVersion(). + /// + /// Pointer to a char. + /// The char as a string. + private static string PtrToStringUtf8(IntPtr ptr) + { + if (ptr == IntPtr.Zero) + { + return ""; + } + int len = 0; + while (Marshal.ReadByte(ptr, len) != 0) + len++; + if (len == 0) + { + return ""; + } + byte[] array = new byte[len]; + Marshal.Copy(ptr, array, 0, len); + return System.Text.Encoding.ASCII.GetString(array); + } + + /// + /// Displays a console message. Used to display C++ SDK messages in Unity's console. + /// + /// + private static void DebugMethod(string message) + { + Debug.Log("[ZED plugin]: " + message); + } + + /// + /// Convert a pointer to a char into an array of bytes. Used to send file names to SDK for SVO recording. + /// + /// Pointer to a char. + /// The array. + private static byte[] StringUtf8ToByte(string str) + { + byte[] array = System.Text.Encoding.ASCII.GetBytes(str); + return array; + } + + /// + /// Gets the max FPS for each resolution setting. Higher FPS will cause lower GPU performance. + /// + /// + /// The resolution + static private uint GetFpsForResolution(RESOLUTION reso) + { + if (reso == RESOLUTION.HD1080) return 30; + else if (reso == RESOLUTION.HD2K) return 15; + else if (reso == RESOLUTION.HD720) return 60; + else if (reso == RESOLUTION.VGA) return 100; + return 30; + } + + /// + /// Get a quaternion from a matrix with a minimum size of 3x3. + /// + /// The matrix. + /// A quaternion which contains the matrix's rotation. + public static Quaternion Matrix4ToQuaternion(Matrix4x4 m) + { + Quaternion q = new Quaternion(); + q.w = Mathf.Sqrt(Mathf.Max(0, 1 + m[0, 0] + m[1, 1] + m[2, 2])) / 2; + q.x = Mathf.Sqrt(Mathf.Max(0, 1 + m[0, 0] - m[1, 1] - m[2, 2])) / 2; + q.y = Mathf.Sqrt(Mathf.Max(0, 1 - m[0, 0] + m[1, 1] - m[2, 2])) / 2; + q.z = Mathf.Sqrt(Mathf.Max(0, 1 - m[0, 0] - m[1, 1] + m[2, 2])) / 2; + q.x *= Mathf.Sign(q.x * (m[2, 1] - m[1, 2])); + q.y *= Mathf.Sign(q.y * (m[0, 2] - m[2, 0])); + q.z *= Mathf.Sign(q.z * (m[1, 0] - m[0, 1])); + return q; + } + + /// + /// Performs a rigid transform. + /// + /// + /// + /// + /// + public static void TransformPose(ref Quaternion quaternion, ref Vector3 translation, ref Quaternion targetQuaternion, ref Vector3 targetTranslation) + { + dllz_transform_pose(ref quaternion, ref translation, ref targetQuaternion, ref targetTranslation); + } + + /// + /// 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) //Found path to the ZED SDK in PC's environmental variables. + { + 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)); //Print that SDK isn't installed. + return false; + } else { //Found DLLs in ZED install directory. + + try { + 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; + } + } + catch(DllNotFoundException) { + + Debug.LogError (ZEDLogMessage.Error2Str (ZEDLogMessage.ERROR.SDK_DEPENDENCIES_ISSUE)); + return false; + } + } + } + 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 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. + /// + /// True, if USB device connected was found, false otherwise. + /// Type. + public static bool CheckUSBDeviceConnected(USB_DEVICE Type) + { + if (dllz_find_usb_device (Type)) + return true; + else + return false; + } + + /// + /// 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; + if (filesFound == null) { + return true; + } + foreach (string dependency in dependenciesNeeded) + { + bool found = false; + foreach (string file in filesFound) + { + if (System.IO.Path.GetFileName(file).Equals(dependency)) + { + found = true; + break; + } + } + + if (!found) + { + isASDKPb = true; + Debug.LogError("[ZED Plugin ] : " + dependency + " is not found"); + } + } + + return isASDKPb; + } + + + /// + /// Private constructor. Initializes lists to hold references to textures and texture requests. + /// + public ZEDCamera() + { + //Create the textures + textures = new Dictionary>(); + texturesRequested = new List(); + } + + /// + /// 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 bool CreateCamera(int cameraID, bool verbose) + { + string infoSystem = SystemInfo.graphicsDeviceType.ToString().ToUpper(); + if (!infoSystem.Equals("DIRECT3D11") && !infoSystem.Equals("OPENGLCORE")) + { + throw new Exception("The graphic library [" + infoSystem + "] is not supported"); + } + CameraID = cameraID; + //tagOneObject += cameraID; + return dllz_create_camera(cameraID, verbose); + } + + /// + /// Closes the camera and deletes all textures. + /// Once destroyed, you need to recreate a camera instance to restart again. + /// + public void Destroy() + { + cameraReady = false; + dllz_close(CameraID); + DestroyAllTexture(); + + } + + /// + /// DLL-friendly version of InitParameters (found in ZEDCommon.cs). + /// + [StructLayout(LayoutKind.Sequential)] + public struct dll_initParameters + { + public sl.INPUT_TYPE inputType; + /// + /// 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. + /// + public int cameraID; + /// + /// 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; + /// + /// True to disable the IMU of the ZED Mini (in case USB2.0 is not available) + /// + [MarshalAs(UnmanagedType.U1)] + public bool cameraDisableIMU; + + /// + /// Copy constructor. Takes values from Unity-suited InitParameters class. + /// + /// + public dll_initParameters(InitParameters init) + { + inputType = init.inputType; + resolution = init.resolution; + cameraFps = init.cameraFPS; + svoRealTimeMode = init.svoRealTimeMode; + coordinateUnit = init.coordinateUnit; + depthMode = init.depthMode; + depthMinimumDistance = init.depthMinimumDistance; + cameraImageFlip = init.cameraImageFlip; + enableRightSideMeasure = init.enableRightSideMeasure; + cameraDisableSelfCalib = init.cameraDisableSelfCalib; + cameraBufferCountLinux = init.cameraBufferCountLinux; + sdkVerbose = init.sdkVerbose; + sdkGPUId = init.sdkGPUId; + cameraID = init.cameraID; + coordinateSystem = init.coordinateSystem; + depthStabilization = init.depthStabilization; + cameraDisableIMU = init.cameraDisableIMU; + } + } + + + /// + /// Checks if the ZED camera is plugged in, opens it, and initializes the projection matix and command buffers for updating textures. + /// + /// 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) + { + initParameters.cameraFPS = (int)fpsMax; + } + + 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(CameraID, ref initP, + new System.Text.StringBuilder(initParameters.pathSVO, initParameters.pathSVO.Length), + new System.Text.StringBuilder(initParameters.ipStream, initParameters.ipStream.Length), + initParameters.portStream, + 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) + { + cameraReady = false; + return (ERROR_CODE)v; + } + + //Set more values if the initialization was successful. + imageWidth = dllz_get_width(CameraID); + imageHeight = dllz_get_height(CameraID); + + GetCalibrationParameters(false); + FillProjectionMatrix(); + baseline = calibrationParametersRectified.Trans[0]; + fov_H = calibrationParametersRectified.leftCam.hFOV * Mathf.Deg2Rad; + fov_V = calibrationParametersRectified.leftCam.vFOV * Mathf.Deg2Rad; + cameraModel = GetCameraModel (); + cameraReady = true; + return (ERROR_CODE)v; + } + + + + /// + /// Fills the projection matrix with the parameters of the ZED. Needs to be called only once. + /// This projection matrix is off-center. + /// + /// + /// + public void FillProjectionMatrix(float zFar = 500, float zNear = 0.1f) + { + CalibrationParameters parameters = GetCalibrationParameters(false); + float fovx = parameters.leftCam.hFOV * Mathf.Deg2Rad; + float fovy = parameters.leftCam.vFOV * Mathf.Deg2Rad; + + float f_imageWidth = (float)ImageWidth; + float f_imageHeight = (float)ImageHeight; + + //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; //Horizontal offset. + projection[0, 3] = 0; + + projection[1, 0] = 0; + 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); //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; + projection[3, 2] = -1; + projection[3, 3] = 0.0f; + + } + + /// + /// 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) + { + return (sl.ERROR_CODE)dllz_grab(CameraID, ref runtimeParameters); + } + + /// + /// 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. + /// + public void ResetSelfCalibration() + { + dllz_reset_self_calibration(CameraID); + } + + + /// + /// Return the INPUT_TYPE currently used + /// + /// + public sl.INPUT_TYPE GetInputType() + { + return (sl.INPUT_TYPE)dllz_get_input_type(CameraID); + } + + /// + /// 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.AVCHD_BASED) + { + return (ERROR_CODE)dllz_enable_recording(CameraID, StringUtf8ToByte(videoFileName), (int)compressionMode); + } + + /// + /// Begins record the images to an SVO or AVI. EnableRecording() needs to be called first. + /// + public Recording_state Record() + { + Recording_state state = new Recording_state(); + dllz_record(CameraID,ref state); + return state; + } + + /// + /// Stops recording to an SVO/AVI, if applicable, and closes the file. + /// + public bool DisableRecording() + { + return dllz_disable_recording(CameraID); + } + + /// + /// 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) + { + fpsMax = (uint)fps; + } + + dllz_set_camera_fps(CameraID,fps); + } + + /// + /// Sets the position of the SVO file currently being read to a desired frame. + /// + /// Index of the desired frame to be decoded. + public void SetSVOPosition(int frame) + { + dllz_set_svo_position(CameraID,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. + /// + /// Filtering value between 0 and 100. + public int GetConfidenceThreshold() + { + return dllz_get_confidence_threshold(CameraID); + } + + /// + /// 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 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(CameraID); + } + + /// + /// 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 in nanoseconds. + public ulong GetCurrentTimeStamp() + { + return dllz_get_current_timestamp(CameraID); + } + + /// + /// Timestamp from the most recent image update. Based on the computer's start time. + /// + /// The timestamp in nanoseconds. + public ulong GetImageUpdaterTimeStamp() + { + return dllz_get_image_updater_time_stamp(CameraID); + } + + /// + /// Get the current position of the SVO being recorded to. + /// + /// Index of the frame being recorded to. + public int GetSVOPosition() + { + return dllz_get_svo_position(CameraID); + } + + /// + /// Gets the total number of frames in the loaded SVO file. + /// + /// 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(CameraID); + } + + /// + /// Gets the closest measurable distance by the camera, according to the camera type and depth map parameters. + /// + /// The nearest possible depth value. + public float GetDepthMinRangeValue() + { + return dllz_get_depth_min_range_value(CameraID); + } + + /// + /// Returns the current maximum distance of depth/disparity estimation. + /// + /// The closest depth + public float GetDepthMaxRangeValue() + { + return dllz_get_depth_max_range_value(CameraID); + } + + /// + /// Initialize and Start the tracking functions + /// + /// 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,bool enableFloorAlignment=false, string areaFilePath = "") + { + sl.ERROR_CODE trackingStatus = sl.ERROR_CODE.CAMERA_NOT_DETECTED; + trackingStatus = (sl.ERROR_CODE)dllz_enable_tracking (CameraID,ref quat, ref vec, enableSpatialMemory, enablePoseSmoothing,enableFloorAlignment, new System.Text.StringBuilder (areaFilePath, areaFilePath.Length)); + return trackingStatus; + } + + /// + /// Reset tracking + /// + /// + /// + /// + public sl.ERROR_CODE ResetTracking(Quaternion rotation, Vector3 translation) + { + sl.ERROR_CODE trackingStatus = sl.ERROR_CODE.CAMERA_NOT_DETECTED; + trackingStatus = (sl.ERROR_CODE)dllz_reset_tracking(CameraID,rotation, translation); + return trackingStatus; + } + + public sl.ERROR_CODE ResetTrackingWithOffset(Quaternion rotation, Vector3 translation,Quaternion rotationOffset, Vector3 translationOffset) + { + sl.ERROR_CODE trackingStatus = sl.ERROR_CODE.CAMERA_NOT_DETECTED; + trackingStatus = (sl.ERROR_CODE)dllz_reset_tracking_with_offset(CameraID,rotation, translation,rotationOffset,translationOffset); + return trackingStatus; + } + + + public sl.ERROR_CODE EstimateInitialPosition(ref Quaternion rotation, ref Vector3 translation) + { + sl.ERROR_CODE status = sl.ERROR_CODE.CAMERA_NOT_DETECTED; + status = (sl.ERROR_CODE)dllz_estimate_initial_position(CameraID,ref rotation, ref translation,2,100); + return status; + } + + + /// + /// Stop the motion tracking, if you want to restart, call enableTracking(). + /// + /// The path to save the area file + public void DisableTracking(string path = "") + { + dllz_disable_tracking (CameraID,new System.Text.StringBuilder (path, path.Length)); + } + + public sl.ERROR_CODE SaveCurrentArea(string path) + { + return (sl.ERROR_CODE)dllz_save_current_area(CameraID,new System.Text.StringBuilder(path, path.Length)); + } + + /// + /// Returns the current state of the area learning saving + /// + /// + public sl.AREA_EXPORT_STATE GetAreaExportState() + { + return (sl.AREA_EXPORT_STATE)dllz_get_area_export_state(CameraID); + } + + /// + /// Register a texture to the base + /// + private void RegisterTexture(Texture2D m_Texture, int type, int mode) + { + TextureRequested t = new TextureRequested(); + + t.type = type; + t.option = mode; + texturesRequested.Add(t); + textures[type].Add(mode, m_Texture); + } + + /// + /// 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)) + { + return textures[(int)TYPE_VIEW.RETRIEVE_IMAGE][(int)mode]; + } + if (!cameraReady) + return null; + + int width = ImageWidth; + int height = imageHeight; + 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; + } + + Texture2D m_Texture; + if (mode == VIEW.LEFT_GREY || mode == VIEW.RIGHT_GREY || mode == VIEW.LEFT_UNRECTIFIED_GREY || mode == VIEW.RIGHT_UNRECTIFIED_GREY) + { + m_Texture = new Texture2D(width, height, TextureFormat.Alpha8, false); + } + else if (mode == VIEW.SIDE_BY_SIDE) + { + m_Texture = new Texture2D(width * 2, height, TextureFormat.RGBA32, false); //Needs to be twice as wide for SBS because there are two images. + } + else + { + m_Texture = new Texture2D(width, height, TextureFormat.RGBA32, false); + } + m_Texture.filterMode = FilterMode.Point; + m_Texture.wrapMode = TextureWrapMode.Clamp; + + m_Texture.Apply(); + + IntPtr idTexture = m_Texture.GetNativeTexturePtr(); + int error = dllz_register_texture_image_type(CameraID,(int)mode, idTexture, resolution); + if (error != 0) + { + throw new Exception("CUDA error:" + error + " if the problem appears again, please contact Stereolabs support."); + } + 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); //Save so you don't make a duplicate if another script needs the texture. + + return m_Texture; + } + + /// + /// 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)) + { + return textures[(int)TYPE_VIEW.RETRIEVE_MEASURE][(int)mode]; + } + if (!cameraReady) + return null; + + Texture2D m_Texture; + int width = ImageWidth; + int height = imageHeight; + if (!((uint)resolution.width == 0 && (uint)resolution.height == 0)) + { + 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) + { + m_Texture = new Texture2D(width, height, TextureFormat.RGBAFloat, false, true); + } + else if (mode == MEASURE.DEPTH || mode == MEASURE.CONFIDENCE || mode == MEASURE.DISPARITY || mode == MEASURE.DEPTH_RIGHT || mode == MEASURE.DISPARITY_RIGHT) + { + m_Texture = new Texture2D(width, height, TextureFormat.RFloat, false, true); + } + else + { + m_Texture = new Texture2D(width, height, TextureFormat.RGBA32, false, true); + } + if (!((uint)resolution.width == 0 && (uint)resolution.height == 0)) + { + m_Texture.filterMode = FilterMode.Bilinear; + } + else + { + m_Texture.filterMode = FilterMode.Point; + } + m_Texture.wrapMode = TextureWrapMode.Clamp; + m_Texture.Apply(); + + IntPtr idTexture = m_Texture.GetNativeTexturePtr(); + + int error = dllz_register_texture_measure_type(CameraID,(int)mode, idTexture, resolution); + + if (error != 0) + { + 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); //Save to avoid duplicates if texture type is needed elsewhere. + + return m_Texture; + } + + /// + /// 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); + return dllz_unregister_texture_image_type(CameraID,(int)view) != 0; + } + + /// + /// 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); + return dllz_unregister_texture_measure_type(CameraID,(int)measure) != 0; + } + + /// + /// 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(CameraID,(int)view)); + } + + /// + /// 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(CameraID,(int)measure)); + } + + /// + /// Destroys a texture and removes its reference in the textures list. + /// + /// 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)) + { + textures[type][option] = null; + textures[type].Remove(option); + if (textures[type].Count == 0) + { + textures.Remove(type); + } + } + } + + /// + /// Destroy all textures that were ever requested. + /// + private void DestroyAllTexture() + { + if (cameraReady) + { + foreach (TextureRequested t in texturesRequested) + { + DestroyTexture(t.type, t.option); + } + texturesRequested.Clear(); + } + } + + + /// + /// Destroy a texture created with CreateTextureImageType(). + /// + /// 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(). + /// + /// Measure type (depth, confidence, etc.) as an integer. + private void DestroyTextureMeasureType(int option) + { + DestroyTexture((int)TYPE_VIEW.RETRIEVE_MEASURE, option); + } + + /// + /// Retrieves a texture that was already created. + /// + /// 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)) + { + return textures[(int)type][mode]; + } + return null; + } + + /// + /// Checks if a texture of a given type has already been created. + /// + /// 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) //Texture can't exist if the ZED hasn't been initialized yet. + { + return textures.ContainsKey((int)type) && textures[type].ContainsKey((int)mode); + } + return false; + } + + + /// + /// 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. + /// + /// 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) + { + dllz_set_confidence_threshold(CameraID,threshold); + } + + /// + /// Sets the maximum distance of depth/disparity estimation. All values beyond will be reported as TOO_FAR and not used. + /// + /// Maximum distance in the units set in the InitParameters used in Init(). + public void SetDepthMaxRangeValue(float distanceMax) + { + dllz_set_depth_max_range_value(CameraID,distanceMax); + } + + /// + /// 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() + { + return dllz_get_camera_fps(CameraID); + } + + + + public CalibrationParameters GetCalibrationParameters(bool raw=false) + { + + IntPtr p = dllz_get_calibration_parameters(CameraID,raw); + + if (p == IntPtr.Zero) + { + return new CalibrationParameters(); + } + CalibrationParameters parameters = (CalibrationParameters)Marshal.PtrToStructure(p, typeof(CalibrationParameters)); + + if (raw) + calibrationParametersRaw = parameters; + else + calibrationParametersRectified = parameters; + + + return parameters; + + } + + /// + /// Gets the ZED camera model (ZED or ZED Mini). + /// + /// Model of the ZED as sl.MODEL. + public sl.MODEL GetCameraModel() + { + return (sl.MODEL)dllz_get_camera_model (CameraID); + } + + /// + /// Gets the ZED's firmware version. + /// + /// Firmware version. + public int GetZEDFirmwareVersion() + { + return dllz_get_zed_firmware(CameraID); + } + + /// + /// Gets the ZED's serial number. + /// + /// Serial number + public int GetZEDSerialNumber() + { + return dllz_get_zed_serial(CameraID); + } + + /// + /// Returns the ZED's vertical field of view in radians. + /// + /// Vertical field of view. + public float GetFOV() + { + return GetCalibrationParameters(false).leftCam.vFOV * Mathf.Deg2Rad; + } + + /// + /// Gets the status of the ZED's self-calibration process (not called, running, failed or success). + /// + /// Self-calibration status. + public ZED_SELF_CALIBRATION_STATE GetSelfCalibrationStatus() + { + return (ZED_SELF_CALIBRATION_STATE)dllz_get_self_calibration_state(CameraID); + } + + /// + /// 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(CameraID); + } + + /// + /// Swaps textures safely between the acquisition and rendering threads. + /// + public void SwapTextures() + { + dllz_swap_textures(CameraID); + } + + /// + /// Timestamp of the images used the last time the ZED wrapper updated textures. + /// + /// + public ulong GetImagesTimeStamp() + { + return dllz_get_updated_textures_timestamp(CameraID); + } + + /// + /// 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(CameraID); + } + + /// + /// Gets the percentage of frames dropped since Grab() was called for the first time. + /// + /// Percentage of frames dropped. + public float GetFrameDroppedPercent() + { + return dllz_get_frame_dropped_percent (CameraID); + } + + /// + /// Gets the position of the camera and the current state of the ZED Tracking. + /// + /// 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(CameraID,ref rotation, ref position, (int)referenceType); + } + + /// + /// Gets the current position of the camera and state of the tracking, with an optional offset to the 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. + /// 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(CameraID,ref rotation, ref translation, ref targetQuaternion, ref targetTranslation, (int)referenceFrame); + } + + + /// + /// 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 (trackingFrame) //Add offsets to account for different tracking frames. + { + case sl.TRACKING_FRAME.LEFT_EYE: + positionOffset = new Vector3(0, 0, 0); + break; + case sl.TRACKING_FRAME.RIGHT_EYE: + positionOffset = new Vector3(Baseline, 0, 0); + break; + case sl.TRACKING_FRAME.CENTER_EYE: + positionOffset = new Vector3(Baseline / 2.0f, 0, 0); + break; + } + + return (TRACKING_STATE)dllz_get_position_at_target_frame(CameraID,ref rotation, ref translation, ref rotationOffset, ref positionOffset, (int)referenceFrame); + } + + /// + /// 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 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(CameraID,ref pose, (int)referenceType); + } + + + /// + /// 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. + /// Prior rotation. + public ERROR_CODE SetIMUOrientationPrior(ref Quaternion rotation) + { + sl.ERROR_CODE trackingStatus = sl.ERROR_CODE.CAMERA_NOT_DETECTED; + trackingStatus = (sl.ERROR_CODE)dllz_set_imu_prior_orientation(CameraID,rotation); + return trackingStatus; + } + + /// + /// Gets the rotation given by the ZED Mini's IMU. Doesn't work if using the original ZED. + /// + /// 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; + err = (sl.ERROR_CODE)dllz_get_internal_imu_orientation(CameraID,ref rotation,(int)referenceTime); + return err; + } + + /// + /// 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 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; + err = (sl.ERROR_CODE)dllz_get_internal_imu_data(CameraID,ref data,(int)referenceTime); + return err; + } + + /// + /// 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; + if (f.Length != 16) return; + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + m[i, j] = f[i * 4 + j]; + } + } + } + + /// + /// Sets a value in the ZED's camera settings. + /// + /// 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) + { + AssertCameraIsReady(); + cameraSettingsManager.SetCameraSettings(CameraID, settings, value, usedefault); + } + + /// + /// 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(); + return cameraSettingsManager.GetCameraSettings(CameraID, settings); + } + + public void ResetCameraSettings() + { + AssertCameraIsReady(); + cameraSettingsManager.ResetCameraSettings(this); + } + + /// + /// 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(this, path); + } + + /// + /// 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); + } + + /// + /// Retrieves camera settings from the ZED camera and loads them into a CameraSettings instance + /// handled by ZEDCameraSettingsManager. + /// + public void RetrieveCameraSettings() + { + cameraSettingsManager.RetrieveSettingsCamera(this); + } + + /// + /// Returns a copy of the camera settings from ZEDCameraSettingsManager. Modifying this copy + /// has no effect on the camera or ZEDCameraSettingsManager. + /// + /// + public ZEDCameraSettings.CameraSettings GetCameraSettings() + { + return cameraSettingsManager.Settings; + } + + + /// + /// Returns if the camera's exposure mode is set to automatic. + /// + /// True if automatic, false if manual. + public bool GetExposureUpdateType() + { + return cameraSettingsManager.auto; + } + + /// + /// Returns if the camera's white balance is set to automatic. + /// + /// True if automatic, false if manual. + public bool GetWhiteBalanceUpdateType() + { + return cameraSettingsManager.whiteBalanceAuto; + } + + /// + /// Applies all the settings registered in the ZEDCameraSettingsManager instance to the actual ZED camera. + /// + public void SetCameraSettings() + { + cameraSettingsManager.SetSettings(this); + } + + /// + /// Checks if the ZED camera is connected. + /// + /// 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()); + } + + /// + /// Gets the version of the currently installed ZED SDK. + /// + /// ZED SDK version as a string in the format MAJOR.MINOR.PATCH. + public static string GetSDKVersion() + { + return PtrToStringUtf8(dllz_get_sdk_version()); + } + + /// + /// Checks if the camera has been initialized and the plugin has been loaded. Throws exceptions otherwise. + /// + private void AssertCameraIsReady() + { + if (!cameraReady) + throw new Exception("ZED camera is not connected or Init() was not called."); + + if (!pluginIsReady) + throw new Exception("Could not resolve ZED plugin dependencies."); + + } + + /// + /// 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() + { + GL.IssuePluginEvent(GetRenderEventFunc(), 1); + } + + + ///////////////////////////// SINGLE PIXEL UTILITY FUNCTIONS //////////////////////////////// + + /// + /// 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) + { + return -1; + } + + float posX = (float)ImageWidth * (float)((float)pixel.x / (float)Screen.width); + float posY = ImageHeight * (1 - (float)pixel.y / (float)Screen.height); + + posX = Mathf.Clamp(posX, 0, ImageWidth); + posY = Mathf.Clamp(posY, 0, ImageHeight); + float d = dllz_get_depth_value(CameraID,(uint)posX, (uint)posY); + return d; + } + + /// + /// 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) //Do nothing if the ZED isn't initialized. + { + return -1; + } + float posX = ImageWidth * (float)pixel.x / (float)Screen.width; + float posY = ImageHeight * (1 - (float)pixel.y / (float)Screen.height); + posX = Mathf.Clamp(posX, 0, ImageWidth); + posY = Mathf.Clamp(posY, 0, ImageHeight); + + return dllz_get_distance_value(CameraID,(uint)posX, (uint)posY); + } + + /// + /// 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) //Do nothing if the ZED isn't initialized. + { + xyz = Vector3.zero; + return false; + } + + float posX = (float)ImageWidth * (float)((float)pixel.x / (float)Screen.width); + float posY = ImageHeight * (1 - (float)pixel.y / (float)Screen.height); + posX = Mathf.Clamp(posX, 0, ImageWidth); + posY = Mathf.Clamp(posY, 0, ImageHeight); + bool r = dllz_get_xyz_value(CameraID,(uint)posX, (uint)posY, out xyz) != 0; + return r; + } + + + /// + /// 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) //Do nothing if the ZED isn't initialized. + { + normal = Vector3.zero; + return false; + } + + float posX = (float)ImageWidth * (float)((float)pixel.x / (float)Screen.width); + float posY = ImageHeight * (1 - (float)pixel.y / (float)Screen.height); + + posX = Mathf.Clamp(posX, 0, ImageWidth); + posY = Mathf.Clamp(posY, 0, ImageHeight); + + bool r = dllz_get_normal_value(CameraID,(uint)posX, (uint)posY, out normal) != 0; + return r; + } + + /// + /// Initializes and begins the spatial mapping processes. + /// + /// 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) + { + sl.ERROR_CODE spatialMappingStatus = ERROR_CODE.FAILURE; + lock (grabLock) + { + spatialMappingStatus = (sl.ERROR_CODE)dllz_enable_spatial_mapping(CameraID,resolution_meter, max_range_meter, System.Convert.ToInt32(saveTexture)); + } + return spatialMappingStatus; + } + + /// + /// Disables the Spatial Mapping process. + /// + public void DisableSpatialMapping() + { + lock (grabLock) + { + dllz_disable_spatial_mapping(CameraID); + } + } + + /// + /// Updates the internal version of the mesh and returns the sizes of the meshes. + /// + /// 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(CameraID,nbVerticesInSubmeshes, nbTrianglesInSubmeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, nbSubmeshMax); + return err; + } + + /// + /// 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 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(CameraID,vertices, triangles, nbSubmeshMax, uvs, textures); + } + + /// + /// 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() + { + dllz_request_mesh_async(CameraID); + } + + /// + /// 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. + public void PauseSpatialMapping(bool status) + { + dllz_pause_spatial_mapping(CameraID,status); + } + + /// + /// Returns the mesh generation status. Useful for knowing when to update and retrieve the mesh. + /// + public sl.ERROR_CODE GetMeshRequestStatus() + { + return (sl.ERROR_CODE)dllz_get_mesh_request_status_async(CameraID); + } + + /// + /// Saves the scanned mesh in a specific file format. + /// + /// 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(CameraID,filename, format); + } + + /// + /// Loads a saved mesh file. ZEDSpatialMapping then configures itself as if the loaded mesh was just scanned. + /// + /// 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(CameraID,filename, nbVerticesInSubmeshes, nbTrianglesInSubmeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, + ref nbTriangles, nbSubmeshMax, textureSize); + } + + /// + /// Filters a mesh to remove triangles while still preserving its overall shape (though less accurate). + /// + /// 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(CameraID,filterParameters, nbVerticesInSubemeshes, nbTrianglesInSubemeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, nbSubmeshMax); + } + + /// + /// 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. + /// + /// 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). + /// Maximum number of submeshes that can be handled. + /// + 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(CameraID,nbVerticesInSubmeshes, nbTrianglesInSubmeshes, ref nbSubmeshes, updatedIndices, ref nbVertices, ref nbTriangles, textureSize, nbSubmeshMax); + } + + /// + /// Gets the current state of spatial mapping. + /// + /// + public SPATIAL_MAPPING_STATE GetSpatialMappingState() + { + return (sl.SPATIAL_MAPPING_STATE)dllz_get_spatial_mapping_state(CameraID); + } + + /// + /// 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; + dllz_spatial_mapping_get_gravity_estimation(CameraID,ref v); + return v; + } + + /// + /// 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). + /// + /// + /// 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(CameraID,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(CameraID,mat.MatPtr, (int)measure, (int)mem, resolution)); + } + + /// + /// 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(CameraID,mat.MatPtr, (int)view, (int)mem, resolution)); + } + + /// + /// 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); + sl.Resolution imageResolution = new sl.Resolution((uint)this.ImageWidth, (uint)this.ImageHeight); + + + Vector4 calibLeft = new Vector4(calib.leftCam.fx, calib.leftCam.fy, calib.leftCam.cx, calib.leftCam.cy); + Vector4 calibRight = new Vector4(calib.rightCam.fx, calib.rightCam.fy, calib.rightCam.cx, calib.rightCam.cy); + + p = dllz_compute_optical_center_offsets(ref calibLeft, ref calibRight, imageResolution, planeDistance); + + if (p == IntPtr.Zero) + { + return new Vector4(); + } + Vector4 parameters = (Vector4)Marshal.PtrToStructure(p, typeof(Vector4)); + return parameters; + + } + + /// + /// Plane Detection + /// + + + /// + /// 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; + Vector3 out_trans= Vector3.zero; + p = dllz_find_floor_plane (CameraID, out out_quat, out out_trans, priorTrans, priorTrans); + plane.Bounds = new Vector3[256]; + playerHeight = 0; + + if (p != IntPtr.Zero) { + plane = (ZEDPlaneGameObject.PlaneData)Marshal.PtrToStructure (p, typeof(ZEDPlaneGameObject.PlaneData)); + playerHeight = out_trans.y; + return (sl.ERROR_CODE)plane.ErrorCode; + } else + return sl.ERROR_CODE.FAILURE; + } + /// + /// 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 (CameraID, vertices, triangles,out numVertices,out numTriangles); + } + + /// + /// 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; + Vector3 out_trans= Vector3.zero; + + float posX = (float)ImageWidth * (float)((float)screenPos.x / (float)Screen.width); + float posY = ImageHeight * (1 - (float)screenPos.y / (float)Screen.height); + posX = Mathf.Clamp(posX, 0, ImageWidth); + posY = Mathf.Clamp(posY, 0, ImageHeight); + + p = dllz_find_plane_at_hit (CameraID, new Vector2(posX,posY),true); + plane.Bounds = new Vector3[256]; + + if (p != IntPtr.Zero) { + plane = (ZEDPlaneGameObject.PlaneData)Marshal.PtrToStructure (p, typeof(ZEDPlaneGameObject.PlaneData)); + return (sl.ERROR_CODE)plane.ErrorCode; + } else + 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 (CameraID, vertices, triangles,out numVertices,out numTriangles); + } + + + //////////////////////// + /// Streaming Module /// + //////////////////////// + + /// + /// Creates an streaming pipeline. + /// + /// + /// Streaming parameters: See sl::StreamingParameters of ZED SDK. See ZED SDK API doc for more informations + /// + /// An ERROR_CODE that defines if the streaming pipe was successfully created + public ERROR_CODE EnableStreaming(STREAMING_CODEC codec = STREAMING_CODEC.AVCHD_BASED, uint bitrate=8000, ushort port=30000, int gopSize=-1, bool adaptativeBitrate=false) + { + int doAdaptBitrate = adaptativeBitrate ? 1 : 0; + return (ERROR_CODE)dllz_enable_streaming(CameraID, codec, bitrate, port, gopSize, doAdaptBitrate); + } + + /// + /// 0 if streaming is not enabled, 1 if streaming is on + /// + /// + public bool IsStreamingEnabled() + { + int res = dllz_is_streaming_enabled(CameraID); + if (res == 1) + return true; + else + return false; + } + + /// + /// Stops the streaming pipeline. + /// + public void DisableStreaming() + { + dllz_disable_streaming(CameraID); + } + + } +} // namespace sl diff --git a/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs.meta b/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs.meta new file mode 100644 index 0000000..62b6712 --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface/ZEDCamera.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8c962c3d2079b7c479f0c169a22ad5da +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/NativeInterface/ZEDCameraSettings.cs b/Assets/ZED/SDK/NativeInterface/ZEDCameraSettings.cs new file mode 100644 index 0000000..57b41b5 --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface/ZEDCameraSettings.cs @@ -0,0 +1,414 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +using System.Runtime.InteropServices; + +/// +/// 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 ZEDCameraSettings +{ + #region DLL Calls + const string nameDll = "sl_unitywrapper"; + [DllImport(nameDll, EntryPoint = "dllz_set_camera_settings")] + private static extern void dllz_set_camera_settings(int id, int mode, int value, int usedefault); + + [DllImport(nameDll, EntryPoint = "dllz_get_camera_settings")] + private static extern int dllz_get_camera_settings(int id, int mode); + + #endregion + + /// + /// 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,int ledStatus = 1) + { + settings = new int[System.Enum.GetNames(typeof(sl.CAMERA_SETTINGS)).Length]; + settings[(int)sl.CAMERA_SETTINGS.BRIGHTNESS] = brightness; + settings[(int)sl.CAMERA_SETTINGS.CONTRAST] = contrast; + settings[(int)sl.CAMERA_SETTINGS.SATURATION] = saturation; + settings[(int)sl.CAMERA_SETTINGS.HUE] = hue; + settings[(int)sl.CAMERA_SETTINGS.WHITEBALANCE] = whiteBalance; + settings[(int)sl.CAMERA_SETTINGS.GAIN] = gain; + settings[(int)sl.CAMERA_SETTINGS.EXPOSURE] = exposure; + settings[(int)sl.CAMERA_SETTINGS.LED_STATUS] = ledStatus; + } + + /// + /// 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]; + settings[(int)sl.CAMERA_SETTINGS.BRIGHTNESS] = other.settings[(int)sl.CAMERA_SETTINGS.BRIGHTNESS]; + settings[(int)sl.CAMERA_SETTINGS.CONTRAST] = other.settings[(int)sl.CAMERA_SETTINGS.CONTRAST]; + settings[(int)sl.CAMERA_SETTINGS.SATURATION] = other.settings[(int)sl.CAMERA_SETTINGS.SATURATION]; + settings[(int)sl.CAMERA_SETTINGS.HUE] = other.settings[(int)sl.CAMERA_SETTINGS.HUE]; + settings[(int)sl.CAMERA_SETTINGS.WHITEBALANCE] = other.settings[(int)sl.CAMERA_SETTINGS.WHITEBALANCE]; + settings[(int)sl.CAMERA_SETTINGS.GAIN] = other.settings[(int)sl.CAMERA_SETTINGS.GAIN]; + settings[(int)sl.CAMERA_SETTINGS.EXPOSURE] = other.settings[(int)sl.CAMERA_SETTINGS.EXPOSURE]; + settings[(int)sl.CAMERA_SETTINGS.LED_STATUS] = other.settings[(int)sl.CAMERA_SETTINGS.LED_STATUS]; + } + + /// + /// 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 + { + return settings[(int)sl.CAMERA_SETTINGS.BRIGHTNESS]; + } + + set + { + settings[(int)sl.CAMERA_SETTINGS.BRIGHTNESS] = value; + } + } + + /// + /// ZED camera's saturation setting. + /// + public int Saturation + { + get + { + return settings[(int)sl.CAMERA_SETTINGS.SATURATION]; + } + + set + { + settings[(int)sl.CAMERA_SETTINGS.SATURATION] = value; + } + } + + /// + /// ZED camera's hue setting. + /// + public int Hue + { + get + { + return settings[(int)sl.CAMERA_SETTINGS.HUE]; + } + + set + { + settings[(int)sl.CAMERA_SETTINGS.HUE] = value; + } + } + + /// + /// ZED camera's contrast setting. + /// + public int Contrast + { + get + { + return settings[(int)sl.CAMERA_SETTINGS.CONTRAST]; + } + + set + { + settings[(int)sl.CAMERA_SETTINGS.CONTRAST] = value; + } + } + + /// + /// ZED camera's gain setting. -1 means automatic. + /// + public int Gain + { + get + { + return settings[(int)sl.CAMERA_SETTINGS.GAIN]; + } + + set + { + settings[(int)sl.CAMERA_SETTINGS.GAIN] = value; + } + } + + /// + /// ZED camera's exposure setting. -1 means automatic. + /// + public int Exposure + { + get + { + return settings[(int)sl.CAMERA_SETTINGS.EXPOSURE]; + } + + set + { + settings[(int)sl.CAMERA_SETTINGS.EXPOSURE] = value; + } + } + + /// + /// ZED camera's white balance setting. -1 means automatic. + /// + public int WhiteBalance + { + get + { + return settings[(int)sl.CAMERA_SETTINGS.WHITEBALANCE]; + } + + set + { + settings[(int)sl.CAMERA_SETTINGS.WHITEBALANCE] = value; + } + } + + /// + /// ZED camera's LED status + /// + public int LEDStatus + { + get + { + return settings[(int)sl.CAMERA_SETTINGS.LED_STATUS]; + } + + set + { + settings[(int)sl.CAMERA_SETTINGS.LED_STATUS] = value; + } + } + + } + /// + /// Reference to the settings container object. + /// + private CameraSettings settings_; + /// + /// Reference to the settings container object. + /// + public CameraSettings Settings + { + get { return settings_.Clone(); } + } + + /// + /// Whether exposure is set to automatic. + /// + public bool auto = 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 ZEDCameraSettings() + { + settings_ = new CameraSettings(); + } + + /// + /// 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) + { + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.BRIGHTNESS, settings_.Brightness, false); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.CONTRAST, settings_.Contrast, false); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.HUE, settings_.Hue, false); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.SATURATION, settings_.Saturation, false); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.GAIN, settings_.Gain, false); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.EXPOSURE, settings_.Exposure, false); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.LED_STATUS, settings_.LEDStatus, false); + if (settings_.WhiteBalance != -1) + { + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.WHITEBALANCE, settings_.WhiteBalance, false); + } + } + } + + + /// + /// Applies all settings from the container to the actual ZED camera. + /// + /// Current instance of the ZEDCamera wrapper. + public void ResetCameraSettings(sl.ZEDCamera zedCamera) + { + if (zedCamera != null) + { + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.BRIGHTNESS, 0, true); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.CONTRAST, 0 , true); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.HUE, 0 , true); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.SATURATION, 0 , true); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.WHITEBALANCE, 0, true); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.EXPOSURE, 0, true); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.GAIN, 0, true); + zedCamera.SetCameraSettings(sl.CAMERA_SETTINGS.LED_STATUS, 1, true); + } + } + /// + /// 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). + /// + /// + /// + public void LoadCameraSettings(sl.ZEDCamera zedCamera, string path = "ZED_Settings.conf") + { + + string[] lines = null; + try + { + lines = System.IO.File.ReadAllLines(path); + } + catch (System.Exception) + { + + } + if (lines == null) return; + + foreach (string line in lines) + { + string[] splittedLine = line.Split('='); + if (splittedLine.Length == 2) + { + string key = splittedLine[0]; + string field = splittedLine[1]; + + if (key == "brightness") + { + settings_.Brightness = int.Parse(field); + } + else if (key == "contrast") + { + settings_.Contrast = int.Parse(field); + } + else if (key == "hue") + { + settings_.Hue = int.Parse(field); + } + else if (key == "saturation") + { + settings_.Saturation = int.Parse(field); + } + else if (key == "whiteBalance") + { + settings_.WhiteBalance = int.Parse(field); + } + else if (key == "gain") + { + settings_.Gain = int.Parse(field); + } + else if (key == "exposure") + { + settings_.Exposure = int.Parse(field); + } + else if (key == "LED") + { + settings_.LEDStatus = int.Parse(field); + } + } + } + SetSettings(zedCamera); + auto = (settings_.Exposure == -1); + whiteBalanceAuto = (settings_.WhiteBalance == -1); + } + + + /// + /// Retrieves current settings from the ZED camera. + /// + /// + public void RetrieveSettingsCamera(sl.ZEDCamera zedCamera) + { + if (zedCamera != null) + { + settings_.Brightness = zedCamera.GetCameraSettings(sl.CAMERA_SETTINGS.BRIGHTNESS); + settings_.Contrast = zedCamera.GetCameraSettings(sl.CAMERA_SETTINGS.CONTRAST); + settings_.Hue = zedCamera.GetCameraSettings(sl.CAMERA_SETTINGS.HUE); + settings_.Saturation = zedCamera.GetCameraSettings(sl.CAMERA_SETTINGS.SATURATION); + settings_.Gain = zedCamera.GetCameraSettings(sl.CAMERA_SETTINGS.GAIN); + settings_.Exposure = zedCamera.GetCameraSettings(sl.CAMERA_SETTINGS.EXPOSURE); + settings_.WhiteBalance = zedCamera.GetCameraSettings(sl.CAMERA_SETTINGS.WHITEBALANCE); + settings_.LEDStatus = zedCamera.GetCameraSettings(sl.CAMERA_SETTINGS.LED_STATUS); + } + } + + /// + /// Applies an individual setting to the ZED camera. + /// + /// 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(int cid, sl.CAMERA_SETTINGS settings, int value, bool usedefault = false) + { + settings_.settings[(int)settings] = !usedefault && value != -1 ? value : -1; + dllz_set_camera_settings(cid, (int)settings, value, System.Convert.ToInt32(usedefault)); + } + + /// + /// Gets the value from an individual ZED camera setting (brightness, contrast, gain, exposure, etc.) + /// + /// Setting to be retrieved. + /// Current value. + public int GetCameraSettings(int cid, sl.CAMERA_SETTINGS settings) + { + settings_.settings[(int)settings] = dllz_get_camera_settings(cid, (int)settings); + return settings_.settings[(int)settings]; + } + + /// + /// 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)) + { + file.WriteLine("brightness=" + settings_.Brightness.ToString()); + file.WriteLine("contrast=" + settings_.Contrast.ToString()); + file.WriteLine("hue=" + settings_.Hue.ToString()); + file.WriteLine("saturation=" + settings_.Saturation.ToString()); + file.WriteLine("whiteBalance=" + settings_.WhiteBalance.ToString()); + file.WriteLine("gain=" + settings_.Gain.ToString()); + file.WriteLine("exposure=" + settings_.Exposure.ToString()); + file.WriteLine("LED=" + settings_.LEDStatus.ToString()); + file.Close(); + } + } +} diff --git a/Assets/ZED/SDK/NativeInterface/ZEDCameraSettings.cs.meta b/Assets/ZED/SDK/NativeInterface/ZEDCameraSettings.cs.meta new file mode 100644 index 0000000..d1acc34 --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface/ZEDCameraSettings.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 306d22426e2d07e498cec95c99c0bfb0 +timeCreated: 1543517563 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs b/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs new file mode 100644 index 0000000..ed3ce73 --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs @@ -0,0 +1,1185 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== + +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 +{ + + public class ZEDCommon + { + public const string NameDLL = "sl_unitywrapper"; + } + + public enum ZED_CAMERA_ID + { + CAMERA_ID_01, + CAMERA_ID_02, + CAMERA_ID_03, + CAMERA_ID_04, + }; + + + public enum INPUT_TYPE + { + INPUT_TYPE_USB, + INPUT_TYPE_SVO, + INPUT_TYPE_STREAM + }; + + /// + /// Constant for plugin. Should not be changed + /// + public enum Constant + { + MAX_CAMERA_PLUGIN = 4, + PLANE_DISTANCE = 10 + }; + + /// + /// 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. + }; + + /// + /// 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; + this.height = (System.UIntPtr)height; + } + + public System.UIntPtr width; + public System.UIntPtr height; + }; + + + /// + /// Pose structure with data on timing and validity in addition to + /// position and rotation. + /// + [StructLayout(LayoutKind.Sequential)] + public struct Pose + { + public bool valid; + public ulong timestap; + public Quaternion rotation; + public Vector3 translation; + public int pose_confidence; + }; + + /// + /// Full IMU data structure. + /// + [StructLayout(LayoutKind.Sequential)] + public struct IMUData + { + /// + /// 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. + /// + public float fx; + /// + /// Focal Y. + /// + public float fy; + /// + /// Optical center X. + /// + public float cx; + /// + /// 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. + /// + public float vFOV; + /// + /// Horizontal field of view after stereo rectification. + /// + public float hFOV; + /// + /// 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'. + /// + public Vector3 Rot; + /// + /// Translation between the two sensors. T[0] is the distance between the two cameras in meters. + /// + public Vector3 Trans; + /// + /// Parameters of the left sensor. + /// + public CameraParameters leftCam; + /// + /// 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 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 milliseconds. + /// + public double current_compression_time; + /// + /// Compression ratio (% of raw size) for the current frame. + /// + public double current_compression_ratio; + /// + /// Average compression time in millisecond since beginning of recording. + /// + public double average_compression_time; + /// + /// Compression ratio (% of raw size) since recording was started. + /// + public double average_compression_ratio; + } + + /// + /// 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_NOT_CALLED, + /// + /// Self-calibration is currently running. + /// + SELF_CALIBRATION_RUNNING, + /// + /// 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 successfully produces coherent values. + /// + SELF_CALIBRATION_SUCCESS + }; + + /// + /// 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 + { + /// + /// Does not compute any depth map. Only rectified stereo images will be available. + /// + NONE, + /// + /// Fastest mode for depth computation. + /// + PERFORMANCE, + /// + /// Balanced quality mode. Depth map is robust in most environment and requires medium compute power. + /// + MEDIUM, + /// + /// Favors accuracy over performance. Requires more compute power. + /// + QUALITY, + /// + /// Native depth. Very accurate, but at a large performance cost. + /// + 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 + { + /// + /// Dsplays regular color images. + /// + VIEW_IMAGE, + /// + /// Displays a greyscale depth map. + /// + VIEW_DEPTH, + /// + /// Displays a normal map. + /// + VIEW_NORMALS + }; + + + /// + /// 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 was successful. + /// + SUCCESS, + /// + /// 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_COMPATIBLE, + /// + /// Not enough GPU memory for this depth mode. Try a different mode (such as PERFORMANCE). + /// + NOT_ENOUGH_GPUMEM, + /// + /// The ZED camera is not plugged in or detected. + /// + CAMERA_NOT_DETECTED, + /// + /// 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). + /// + INVALID_RESOLUTION, + /// + /// 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. + /// + CALIBRATION_FILE_NOT_AVAILABLE, + /// + /// ZED calibration file is not valid. Try downloading the factory one or recalibrating using the ZED Calibration tool. + /// + INVALID_CALIBRATION_FILE, + /// + /// The provided SVO file is not valid. + /// + INVALID_SVO_FILE, + /// + /// An SVO recorder-related error occurred (such as not enough free storage or an invalid file path). + /// + SVO_RECORDING_ERROR, + /// + /// An SVO related error when NVIDIA based compression cannot be loaded + /// + SVO_UNSUPPORTED_COMPRESSION, + /// + /// The requested coordinate system is not available. + /// + INVALID_COORDINATE_SYSTEM, + /// + /// The firmware of the ZED is out of date. Update to the latest version. + /// + INVALID_FIRMWARE, + /// + /// 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. + /// + NOT_A_NEW_FRAME, + /// + /// 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. + /// + CAMERA_NOT_INITIALIZED, + /// + /// Your NVIDIA driver is too old and not compatible with your current CUDA version. + /// + NVIDIA_DRIVER_OUT_OF_DATE, + /// + /// The function call is not valid in the current context. Could be a missing a call to sl::Camera::open. + /// + INVALID_FUNCTION_CALL, + /// + /// The SDK wasn't able to load its dependencies, the installer should be launched. + /// + CORRUPTED_SDK_INSTALLATION, + /// + /// The installed SDK is not the SDK used to compile the program. + /// + INCOMPATIBLE_SDK_VERSION, + /// + /// The given area file does not exist. Check the file path. + /// + INVALID_AREA_FILE, + /// + /// 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 set up. + /// + CAMERA_FAILED_TO_SETUP, + /// + /// 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 in use by another process. + /// + CAMERA_ALREADY_IN_USE, + /// + /// 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, + /// + /// Missing or corrupted AI module ressources. + /// Please reinstall the ZED SDK with the AI (object detection) module to fix this issue + /// + AI_MODULE_NOT_AVAILABLE, + /// + /// The cuDNN library cannot be loaded, or is not compatible with this version of the ZED SDK + /// + INCOMPATIBLE_CUDNN_VERSION, + /// + /// End of error code. Used before init has been called. + /// + ERROR_CODE_LAST + }; + + + /// + /// Represents the available resolution options. + /// + public enum RESOLUTION + { + /// + /// 2208*1242. Supported frame rate: 15 FPS. + /// + HD2K, + /// + /// 1920*1080. Supported frame rates: 15, 30 FPS. + /// + HD1080, + /// + /// 1280*720. Supported frame rates: 15, 30, 60 FPS. + /// + HD720, + /// + /// 672*376. Supported frame rates: 15, 30, 60, 100 FPS. + /// + VGA + }; + + + /// + /// Types of compatible ZED cameras. + /// + public enum MODEL + { + /// + /// Original ZED camera. + /// + ZED, + /// + /// ZED Mini. + /// + ZED_M + }; + + /// + /// 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 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. 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 + }; + + /// + /// 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. As a ZEDMat, MAT_TYPE is set to MAT_TYPE_8U_C4. + /// + LEFT, + /// + /// Right RGBA image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C4. + /// + RIGHT, + /// + /// Left GRAY image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C1. + /// + LEFT_GREY, + /// + /// Right GRAY image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C1. + /// + RIGHT_GREY, + /// + /// Left RGBA unrectified image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C4. + /// + LEFT_UNRECTIFIED, + /// + /// Right RGBA unrectified image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C4. + /// + RIGHT_UNRECTIFIED, + /// + /// Left GRAY unrectified image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C1. + /// + LEFT_UNRECTIFIED_GREY, + /// + /// Right GRAY unrectified image. As a ZEDMat, MAT_TYPE is set to sl::MAT_TYPE_8U_C1. + /// + RIGHT_UNRECTIFIED_GREY, + /// + /// 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. 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. 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. 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. 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. 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 + }; + + /// + /// Lists available camera settings for the ZED camera (contrast, hue, saturation, gain, etc.) + /// + public enum CAMERA_SETTINGS + { + /// + /// Brightness control. Value should be between 0 and 8. + /// + BRIGHTNESS, + /// + /// Contrast control. Value should be between 0 and 8. + /// + CONTRAST, + /// + /// Hue control. Value should be between 0 and 11. + /// + HUE, + /// + /// Saturation control. Value should be between 0 and 8 + /// + SATURATION, + /// + /// 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, + /// + /// 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, + /// + /// Color temperature control. Value should be between 2800 and 6500 with a step of 100. + /// + WHITEBALANCE, + /// + /// Defines if the white balance is in automatic mode or not. + /// + AUTO_WHITEBALANCE, + /// + /// front LED status (1==enable, 0 == disable) + /// + LED_STATUS + }; + + /// + /// 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. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. + /// + DISPARITY, + /// + /// Depth map. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. + /// + DEPTH, + /// + /// Certainty/confidence of the disparity map. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. + /// + CONFIDENCE, + /// + /// 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. 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. 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. 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. 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. 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 the right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. + /// + DISPARITY_RIGHT, + /// + /// Depth map for right sensor. As a ZEDMat, MAT_TYPE is set to MAT_32F_C1. + /// + DEPTH_RIGHT, + /// + /// 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. 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. 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. 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. 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. As a ZEDMat, MAT_TYPE is set to MAT_32F_C4. + /// Channel 4 is empty (set to 0). + /// + NORMALS_RIGHT + + }; + + + /// + /// Categories indicating when a timestamp is captured. + /// + public enum TIME_REFERENCE + { + /// + /// Timestamp from when the image was received over USB from the camera, defined + /// by when the entire image was available in memory. + /// + IMAGE, + /// + /// Timestamp from when the relevant function was called. + /// + CURRENT + }; + + /// + /// Reference frame (world or camera) for tracking and depth sensing. + /// + public enum REFERENCE_FRAME + { + /// + /// Matrix contains the total displacement from the world origin/the first tracked point. + /// + WORLD, + /// + /// Matrix contains the displacement from the previous camera position to the current one. + /// + CAMERA + }; + + /// + /// Possible states of the ZED's Tracking system. + /// + public enum TRACKING_STATE + { + /// + /// Tracking is searching for a match from the database to relocate to a previously known position. + /// + TRACKING_SEARCH, + /// + /// Tracking is operating normally; tracking data should be correct. + /// + TRACKING_OK, + /// + /// Tracking is not enabled. + /// + TRACKING_OFF + } + + /// + /// SVO compression modes. + /// + public enum SVO_COMPRESSION_MODE + { + /// + /// RAW images; no compression. This option can lead to extremely large file sizes. + /// + RAW_BASED, + /// + /// Lossless compression based on png/zstd. Average size = 42% of RAW. + /// + LOSSLESS_BASED, + /// + /// Lossy compression based on jpeg. Average size = 22% of RAW. + /// + LOSSY_BASED, + /// + /// AVCHD Based compression (H264). Available since ZED SDK 2.7 + /// + AVCHD_BASED, + /// + /// HEVC Based compression (H265). Available since ZED SDK 2.7 + /// + HEVC_BASED, + } + + + /// + /// Streaming codecs + /// + public enum STREAMING_CODEC + { + /// + /// AVCHD Based compression (H264) + /// + AVCHD_BASED, + /// + /// HEVC Based compression (H265) + /// + HEVC_BASED + } + + /// + /// Mesh formats that can be saved/loaded with spatial mapping. + /// + public enum MESH_FILE_FORMAT + { + /// + /// Contains only vertices and faces. + /// + PLY, + /// + /// Contains only vertices and faces, encoded in binary. + /// + BIN, + /// + /// Contains vertices, normals, faces, and texture information (if possible). + /// + OBJ + } + + /// + /// Presets for filtering meshes scannedw ith spatial mapping. Higher values reduce total face count by more. + /// + public enum FILTER + { + /// + /// Soft decimation and smoothing. + /// + LOW, + /// + /// Decimate the number of faces and apply a soft smooth. + /// + MEDIUM, + /// + /// Drastically reduce the number of faces. + /// + HIGH, + } + + /// + /// Possible states of the ZED's Spatial Mapping system. + /// + public enum SPATIAL_MAPPING_STATE + { + /// + /// Spatial mapping is initializing. + /// + SPATIAL_MAPPING_STATE_INITIALIZING, + /// + /// Depth and tracking data were correctly integrated into the fusion algorithm. + /// + SPATIAL_MAPPING_STATE_OK, + /// + /// Maximum memory dedicated to scanning has been reached; the mesh will no longer be updated. + /// + SPATIAL_MAPPING_STATE_NOT_ENOUGH_MEMORY, + /// + /// EnableSpatialMapping() wasn't called (or the scanning was stopped and not relaunched). + /// + SPATIAL_MAPPING_STATE_NOT_ENABLED, + /// + /// 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 + } + + /// + /// Units used by the SDK for measurements and tracking. METER is best to stay consistent with Unity. + /// + public enum UNIT + { + /// + /// International System, 1/1000 meters. + /// + MILLIMETER, + /// + /// International System, 1/100 meters. + /// + CENTIMETER, + /// + /// International System, 1/1 meters. + /// + METER, + /// + /// Imperial Unit, 1/12 feet. + /// + INCH, + /// + /// Imperial Unit, 1/1 feet. + /// + FOOT + } + + /// + /// 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 + { + public sl.INPUT_TYPE inputType; + /// + /// Resolution the ZED will be set to. + /// + public sl.RESOLUTION resolution; + /// + /// Requested FPS for this resolution. Setting it to 0 will choose the default FPS for this resolution. + /// + public int cameraFPS; + /// + /// ID for identifying which of multiple connected ZEDs to use. + /// + public int cameraID; + /// + /// Path to a recorded SVO file to play, including filename. + /// + public string pathSVO = ""; + /// + /// In SVO playback, this mode simulates a live camera and consequently skipped frames if the computation framerate is too slow. + /// + public bool svoRealTimeMode; + /// + /// 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. + /// LEFT_HANDED_Y_UP is recommended to match Unity's coordinates. + /// + 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; + /// + /// Defines if images are horizontally flipped. + /// + public bool cameraImageFlip; + /// + /// Defines if measures relative to the right sensor should be computed (needed for MEASURE__RIGHT). + /// + public bool enableRightSideMeasure; + /// + /// 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; + /// + /// 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. + /// + public bool sdkVerbose; + /// + /// ID of the graphics card on which the ZED's computations will be performed. + /// + public int sdkGPUId; + /// + /// If set to verbose, the filename of the log file into which the SDK will store its text output. + /// + public string sdkVerboseLogFile = ""; + /// + /// 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 = ""; + /// + /// True to stabilize the depth map. Recommended. + /// + public bool cameraDisableIMU; + /// + /// Path to a recorded SVO file to play, including filename. + /// + public string ipStream = ""; + /// + /// Path to a recorded SVO file to play, including filename. + /// + public ushort portStream = 30000; + + /// + /// Constructor. Sets default initialization parameters recommended for Unity. + /// + public InitParameters() + { + this.inputType = sl.INPUT_TYPE.INPUT_TYPE_USB; + this.resolution = RESOLUTION.HD720; + this.cameraFPS = 60; + this.cameraID = 0; + this.pathSVO = ""; + this.svoRealTimeMode = false; + this.coordinateUnit = UNIT.METER; + this.coordinateSystem = COORDINATE_SYSTEM.IMAGE; + this.depthMode = DEPTH_MODE.PERFORMANCE; + this.depthMinimumDistance = -1; + this.cameraImageFlip = false; + this.cameraDisableSelfCalib = false; + this.cameraBufferCountLinux = 4; + this.sdkVerbose = false; + this.sdkGPUId = -1; + this.sdkVerboseLogFile = ""; + this.enableRightSideMeasure = false; + this.depthStabilization = true; + this.optionalSettingsPath = ""; + this.cameraDisableIMU = false; + this.ipStream = ""; + this.portStream = 30000; + } + + } + /// + /// 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 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. Recommended. Used in Unity with DirectX. + /// + LEFT_HANDED_Y_UP, + /// + /// Right-Handed with Y pointing up and Z backward. Used in OpenGL. + /// + RIGHT_HANDED_Y_UP, + /// + /// Right-Handed with Z pointing up and Y forward. Used in 3DSMax. + /// + RIGHT_HANDED_Z_UP, + /// + /// Left-Handed with Z axis pointing up and X forward. Used in Unreal Engine. + /// + LEFT_HANDED_Z_UP + } + + /// + /// 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 + { + /// + /// Spatial memory file has been successfully created. + /// + AREA_EXPORT_STATE_SUCCESS, + /// + /// Spatial memory file is currently being written to. + /// + AREA_EXPORT_STATE_RUNNING, + /// + /// Spatial memory file export has not been called. + /// + AREA_EXPORT_STATE_NOT_STARTED, + /// + /// Spatial memory contains no data; the file is empty. + /// + AREA_EXPORT_STATE_FILE_EMPTY, + /// + /// Spatial memory file has not been written to because of a bad file name. + /// + AREA_EXPORT_STATE_FILE_ERROR, + /// + /// Spatial memory has been disabled, so no file can be created. + /// + AREA_EXPORT_STATE_SPATIAL_MEMORY_DISABLED + }; + + + /// + /// 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. + /// + [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). + /// + [FieldOffset(16)] + public sl.REFERENCE_FRAME measure3DReferenceFrame; + /// + /// Defines whether the depth map should be computed. + /// + [MarshalAs(UnmanagedType.U1)] + [FieldOffset(20)] + public bool enableDepth; + /// + /// Defines whether the point cloud should be computed (including XYZRGBA). + /// + [MarshalAs(UnmanagedType.U1)] + [FieldOffset(21)] + public bool enablePointCloud; + } + + /// + /// 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 + }; + + + /// + /// Types of USB device brands. + /// + 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 + }; + + + + + +}// end namespace sl diff --git a/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs.meta b/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs.meta new file mode 100644 index 0000000..0674ba4 --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface/ZEDCommon.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 24953f3a6ef7c3e43986be071faf8692 +timeCreated: 1507318646 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/NativeInterface/ZEDMat.cs b/Assets/ZED/SDK/NativeInterface/ZEDMat.cs new file mode 100644 index 0000000..eaa5bb1 --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface/ZEDMat.cs @@ -0,0 +1,875 @@ +//======= Copyright (c) Stereolabs Corporation, All rights reserved. =============== +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 + { + public byte r; + 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 + { + [MarshalAs(UnmanagedType.U1)] + public byte r; + [MarshalAs(UnmanagedType.U1)] + public byte g; + [MarshalAs(UnmanagedType.U1)] + public byte b; + [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 + { + public float r; + 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 + { + public float r; + public float g; + public float b; + 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 + { + /// + /// 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.*/ + /// + /// 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 + { + /// + /// 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")] + private static extern IntPtr dllz_mat_create_new(sl.Resolution resolution, int type, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_create_new_empty")] + private static extern IntPtr dllz_mat_create_new_empty(); + + + [DllImport(nameDll, EntryPoint = "dllz_mat_is_init")] + private static extern bool dllz_mat_is_init(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_free")] + private static extern bool dllz_mat_free(System.IntPtr ptr, int type); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_infos")] + private static extern bool dllz_mat_get_infos(System.IntPtr ptr, byte[] buffer); + + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_value_float")] + private static extern int dllz_mat_get_value_float(System.IntPtr ptr, int x, int y, out float value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_get_value_float2")] + private static extern int dllz_mat_get_value_float2(System.IntPtr ptr, int x, int y, out float2 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_get_value_float3")] + private static extern int dllz_mat_get_value_float3(System.IntPtr ptr, int x, int y, out float3 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_get_value_float4")] + private static extern int dllz_mat_get_value_float4(System.IntPtr ptr, int x, int y, out float4 value, int mem); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_value_uchar")] + private static extern int dllz_mat_get_value_uchar(System.IntPtr ptr, int x, int y, out byte value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_get_value_uchar2")] + private static extern int dllz_mat_get_value_uchar2(System.IntPtr ptr, int x, int y, out char2 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_get_value_uchar3")] + private static extern int dllz_mat_get_value_uchar3(System.IntPtr ptr, int x, int y, out char3 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_get_value_uchar4")] + private static extern int dllz_mat_get_value_uchar4(System.IntPtr ptr, int x, int y, out char4 value, int mem); + + + [DllImport(nameDll, EntryPoint = "dllz_mat_set_value_float")] + private static extern int dllz_mat_set_value_float(System.IntPtr ptr, int x, int y, ref float value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_value_float2")] + private static extern int dllz_mat_set_value_float2(System.IntPtr ptr, int x, int y, ref float2 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_value_float3")] + private static extern int dllz_mat_set_value_float3(System.IntPtr ptr, int x, int y, ref float3 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_value_float4")] + private static extern int dllz_mat_set_value_float4(System.IntPtr ptr, int x, int y, ref float4 value, int mem); + + [DllImport(nameDll, EntryPoint = "dllz_mat_set_value_uchar")] + private static extern int dllz_mat_set_value_uchar(System.IntPtr ptr, int x, int y, ref byte value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_value_uchar2")] + private static extern int dllz_mat_set_value_uchar2(System.IntPtr ptr, int x, int y, ref char2 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_value_uchar3")] + private static extern int dllz_mat_set_value_uchar3(System.IntPtr ptr, int x, int y, ref char3 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_value_uchar4")] + private static extern int dllz_mat_set_value_uchar4(System.IntPtr ptr, int x, int y, ref char4 value, int mem); + + + [DllImport(nameDll, EntryPoint = "dllz_mat_set_to_float")] + private static extern int dllz_mat_set_to_float(System.IntPtr ptr, ref float value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_to_float2")] + private static extern int dllz_mat_set_to_float2(System.IntPtr ptr, ref float2 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_to_float3")] + private static extern int dllz_mat_set_to_float3(System.IntPtr ptr, ref float3 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_to_float4")] + private static extern int dllz_mat_set_to_float4(System.IntPtr ptr, ref float4 value, int mem); + + [DllImport(nameDll, EntryPoint = "dllz_mat_set_to_uchar")] + private static extern int dllz_mat_set_to_uchar(System.IntPtr ptr, ref byte value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_to_uchar2")] + private static extern int dllz_mat_set_to_uchar2(System.IntPtr ptr, ref char2 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_to_uchar3")] + private static extern int dllz_mat_set_to_uchar3(System.IntPtr ptr, ref char3 value, int mem); + [DllImport(nameDll, EntryPoint = "dllz_mat_set_to_uchar4")] + private static extern int dllz_mat_set_to_uchar4(System.IntPtr ptr, ref char4 value, int mem); + + [DllImport(nameDll, EntryPoint = "dllz_mat_update_cpu_from_gpu")] + private static extern int dllz_mat_update_cpu_from_gpu(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_update_gpu_from_cpu")] + private static extern int dllz_mat_update_gpu_from_cpu(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_read")] + private static extern int dllz_mat_read(System.IntPtr ptr, string filePath); + + [DllImport(nameDll, EntryPoint = "dllz_mat_write")] + private static extern int dllz_mat_write(System.IntPtr ptr, string filePath); + + [DllImport(nameDll, EntryPoint = "dllz_mat_copy_to")] + private static extern int dllz_mat_copy_to(System.IntPtr ptr, System.IntPtr dest, int cpyType); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_width")] + private static extern int dllz_mat_get_width(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_height")] + private static extern int dllz_mat_get_height(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_channels")] + private static extern int dllz_mat_get_channels(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_memory_type")] + private static extern int dllz_mat_get_memory_type(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_pixel_bytes")] + private static extern int dllz_mat_get_pixel_bytes(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_step")] + private static extern int dllz_mat_get_step(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_step_bytes")] + private static extern int dllz_mat_get_step_bytes(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_width_bytes")] + private static extern int dllz_mat_get_width_bytes(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_is_memory_owner")] + private static extern bool dllz_mat_is_memory_owner(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_resolution")] + private static extern sl.Resolution dllz_mat_get_resolution(System.IntPtr ptr); + + [DllImport(nameDll, EntryPoint = "dllz_mat_alloc")] + private static extern void dllz_mat_alloc(System.IntPtr ptr, int width, int height, int type, int mem); + + [DllImport(nameDll, EntryPoint = "dllz_mat_set_from")] + private static extern int dllz_mat_set_from(System.IntPtr ptr, System.IntPtr source, int copyType); + + [DllImport(nameDll, EntryPoint = "dllz_mat_get_ptr")] + private static extern System.IntPtr dllz_mat_get_ptr(System.IntPtr ptr, int mem); + + [DllImport(nameDll, EntryPoint = "dllz_mat_clone")] + private static extern void dllz_mat_clone(System.IntPtr ptr, System.IntPtr ptrSource); + + #endregion + + /// + /// Returns the internal ptr of a Mat. + /// + private System.IntPtr _matInternalPtr; + /// + /// Returns the internal ptr of a Mat. + /// + public IntPtr MatPtr + { + get { return _matInternalPtr; } + } + + /// + /// Creates an empty Mat. + /// + public ZEDMat() + { + _matInternalPtr = dllz_mat_create_new_empty(); + } + + /// + /// 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."); + } + _matInternalPtr = ptr; + } + + /// + /// 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 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)); + } + + /// + /// True if the Mat has been initialized. + /// + /// + public bool IsInit() + { + return dllz_mat_is_init(_matInternalPtr); + } + + /// + /// 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); + _matInternalPtr = System.IntPtr.Zero; + } + + /// + /// Copies data from the GPU to the CPU, if possible. + /// + /// + public sl.ERROR_CODE UpdateCPUFromGPU() + { + return (sl.ERROR_CODE)dllz_mat_update_cpu_from_gpu(_matInternalPtr); + } + + /// + /// Copies data from the CPU to the GPU, if possible. + /// + /// + public sl.ERROR_CODE UpdateGPUFromCPU() + { + return (sl.ERROR_CODE)dllz_mat_update_gpu_from_cpu(_matInternalPtr); + } + + /// + /// Returns information about the Mat. + /// + /// String providing Mat information. + public string GetInfos() + { + byte[] buf = new byte[300]; + dllz_mat_get_infos(_matInternalPtr, buf); + return System.Text.Encoding.ASCII.GetString(buf); + } + + /// + /// Copies data from this Mat to another Mat (deep 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. Supports .png and .jpeg. Only works if Mat has access to MEM_CPU. + /// + /// 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 into a file as an image. Only works if Mat has access to MEM_CPU. + /// + /// 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); + } + + /// + /// Returns the width of the matrix. + /// + /// + public int GetWidth() + { + return dllz_mat_get_width(_matInternalPtr); + } + + /// + /// Returns the height of the matrix. + /// + /// + public int GetHeight() + { + return dllz_mat_get_height(_matInternalPtr); + } + + /// + /// Returns the number of values/channels stored in each pixel. + /// + /// Number of values/channels. + public int GetChannels() + { + return dllz_mat_get_channels(_matInternalPtr); + } + + /// + /// 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/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 - how many bytes make up each row of pixels. + /// + /// + public int GetStepBytes() + { + return dllz_mat_get_step_bytes(_matInternalPtr); + } + + /// + /// Returns the size of each row in bytes. + /// + /// + public int GetWidthBytes() + { + return dllz_mat_get_width_bytes(_matInternalPtr); + } + + /// + /// Returns the type of memory (CPU and/or GPU). + /// + /// + public MEM GetMemoryType() + { + return (MEM)dllz_mat_get_memory_type(_matInternalPtr); + } + + /// + /// Returns whether the Mat is the owner of the memory it's accessing. + /// + /// + 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 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 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 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); + } + + public System.IntPtr GetPtr(MEM mem = MEM.MEM_CPU) + { + return dllz_mat_get_ptr(_matInternalPtr, (int)mem); + } + + /// + /// Duplicates a Mat by copying all its data into a new one (deep copy). + /// + /// + public void Clone(ZEDMat source) + { + dllz_mat_clone(_matInternalPtr, source._matInternalPtr); + } + + /************ GET VALUES *********************/ + //Cannot send values by template due to a covariant issue with an out needed. + + /// + /// 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. (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. (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. (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. (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. (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. (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. (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))); + } + /***************************************************************************************/ + + + /************ SET VALUES *********************/ + //Cannot send values by template due to a covariant issue with an out needed. + + /// + /// 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. (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. (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. (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. (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. (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. (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. (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))); + } + /***************************************************************************************/ + + /************ SET TO *********************/ + //Cannot send values by template due to a covariant issue with an out needed. + + /// + /// 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))); + } + + /// + /// 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))); + } + + /// + /// 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))); + } + + /// + /// 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))); + } + + /// + /// 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))); + } + + /// + /// 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))); + } + + /// + /// 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))); + } + + /// + /// 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/Assets/ZED/SDK/NativeInterface/ZEDMat.cs.meta b/Assets/ZED/SDK/NativeInterface/ZEDMat.cs.meta new file mode 100644 index 0000000..edf4b13 --- /dev/null +++ b/Assets/ZED/SDK/NativeInterface/ZEDMat.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: db449d36144265e4381b777723879839 +timeCreated: 1507141803 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Plugins.meta b/Assets/ZED/SDK/Plugins.meta new file mode 100644 index 0000000..b98e651 --- /dev/null +++ b/Assets/ZED/SDK/Plugins.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a3c537bfa7be65a4985f998f0592f591 +folderAsset: yes +timeCreated: 1507304970 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin.meta b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin.meta new file mode 100644 index 0000000..99798e3 --- /dev/null +++ b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2ede823f097572e44b14672873843301 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29.meta b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29.meta new file mode 100644 index 0000000..ada90d2 --- /dev/null +++ b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: a3ed71d839f646d4d81b56f6c3df8ceb +folderAsset: yes +timeCreated: 1561411759 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/actions.json b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/actions.json new file mode 100644 index 0000000..25a0aa8 --- /dev/null +++ b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/actions.json @@ -0,0 +1,58 @@ +{ + "actions": [ + { + "name": "/actions/zed-default/in/Grab", + "type": "boolean" + }, + { + "name": "/actions/zed-default/in/Pose", + "type": "pose" + }, + { + "name": "/actions/zed-default/in/NavigateUI", + "type": "vector2" + }, + { + "name": "/actions/zed-default/in/Click", + "type": "boolean" + }, + { + "name": "/actions/zed-default/in/Back", + "type": "boolean" + }, + { + "name": "/actions/zed-default/in/Fire", + "type": "boolean" + }, + { + "name": "/actions/zed-default/out/Haptic", + "type": "vibration" + }, + { + "name": "/actions/mixedreality/in/ExternalCamera", + "type": "pose", + "requirement": "optional" + } + ], + "action_sets": [ + { + "name": "/actions/zed-default", + "usage": "single" + }, + { + "name": "/actions/mixedreality", + "usage": "single" + } + ], + "localization": [ + { + "language_tag": "en_US", + "/actions/platformer/in/Jump": "Jump", + "/actions/zed-default/in/Fire": "Fire", + "/actions/zed-default/in/Back": "Back", + "/actions/zed-default/in/Click": "Click", + "/actions/zed-default/in/Grab": "Grab", + "/actions/zed-default/in/NavigateUI": "NavigateUI" + } + ] +} \ No newline at end of file diff --git a/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/actions.json.meta b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/actions.json.meta new file mode 100644 index 0000000..d18a3d2 --- /dev/null +++ b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/actions.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5d8dced29508d384abc84add1ca79757 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/steamvr_partial_manifest.json b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/steamvr_partial_manifest.json new file mode 100644 index 0000000..6337c4f --- /dev/null +++ b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/steamvr_partial_manifest.json @@ -0,0 +1,7 @@ +{ + "name": "ZED_Unity_Plugin", + "version": 29, + "overwriteOld": false, + "removeUnused": false, + "imported": false +} \ No newline at end of file diff --git a/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/steamvr_partial_manifest.json.meta b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/steamvr_partial_manifest.json.meta new file mode 100644 index 0000000..dd19ec6 --- /dev/null +++ b/Assets/ZED/SDK/Plugins/SteamVR_ZED_Unity_Plugin/29/steamvr_partial_manifest.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a415d2697b71db749bd933570e60be43 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Plugins/win64.meta b/Assets/ZED/SDK/Plugins/win64.meta new file mode 100644 index 0000000..828b343 --- /dev/null +++ b/Assets/ZED/SDK/Plugins/win64.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 37f44ebe14993464c91a6e6274258609 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll b/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll new file mode 100644 index 0000000000000000000000000000000000000000..45624b3df0a5c0f9abce3915da071d5eec019848 GIT binary patch literal 379392 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 E07Yuywg3PC literal 0 HcmV?d00001 diff --git a/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll.meta b/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll.meta new file mode 100644 index 0000000..3967ca7 --- /dev/null +++ b/Assets/ZED/SDK/Plugins/win64/sl_unitywrapper.dll.meta @@ -0,0 +1,27 @@ +fileFormatVersion: 2 +guid: c9a93f5ea7d8704448208b35a5240ec4 +timeCreated: 1553884723 +licenseType: Pro +PluginImporter: + serializedVersion: 2 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + isOverridable: 0 + platformData: + data: + first: + Any: + second: + enabled: 1 + settings: {} + data: + first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Shaders.meta b/Assets/ZED/SDK/Shaders.meta new file mode 100644 index 0000000..e179ca0 --- /dev/null +++ b/Assets/ZED/SDK/Shaders.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f6cc4e77c93ec5446bc7f7dff74d9990 +folderAsset: yes +timeCreated: 1507731048 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader b/Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader new file mode 100644 index 0000000..9c60e22 --- /dev/null +++ b/Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader @@ -0,0 +1,54 @@ +Shader "ZED/Unlit BGRA" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags { "RenderType"="Opaque" } + + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + float4 vertex : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + int _eye; + v2f vert (appdata v) + { + + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + + return o; + } + + float4 frag (v2f i) : SV_Target + { + return tex2D(_MainTex, float2(i.uv.x, 1 - i.uv.y)).bgra; + } + ENDCG + } + } +} diff --git a/Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader.meta b/Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader.meta new file mode 100644 index 0000000..e51e603 --- /dev/null +++ b/Assets/ZED/SDK/Shaders/ZED_Unlit_BGRA.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 22452c6b17a58c84cb92a9c44daee63f +timeCreated: 1494426850 +licenseType: Free +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 4f3a746..49cb262 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -47,12 +47,12 @@ PlayerSettings: defaultScreenWidthWeb: 960 defaultScreenHeightWeb: 600 m_StereoRenderingPath: 0 - m_ActiveColorSpace: 0 + m_ActiveColorSpace: 1 m_MTRendering: 1 m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 - displayResolutionDialog: 0 + displayResolutionDialog: 2 iosUseCustomAppBackgroundBehavior: 0 iosAllowHTTPDownload: 1 allowedAutorotateToPortrait: 1 @@ -81,7 +81,7 @@ PlayerSettings: bakeCollisionMeshes: 0 forceSingleInstance: 0 useFlipModelSwapchain: 1 - resizableWindow: 0 + resizableWindow: 1 useMacAppStoreValidation: 0 macAppStoreCategory: public.app-category.games gpuSkinning: 1 @@ -549,7 +549,8 @@ PlayerSettings: webGLLinkerTarget: 1 webGLThreadsSupport: 0 webGLWasmStreaming: 0 - scriptingDefineSymbols: {} + scriptingDefineSymbols: + 1: platformArchitecture: {} scriptingBackend: {} il2cppCompilerConfiguration: {} diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset index ed26313..b62e55e 100644 --- a/ProjectSettings/QualitySettings.asset +++ b/ProjectSettings/QualitySettings.asset @@ -18,7 +18,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 - blendWeights: 1 + skinWeights: 1 textureQuality: 1 anisotropicTextures: 0 antiAliasing: 0 @@ -53,7 +53,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 - blendWeights: 2 + skinWeights: 2 textureQuality: 0 anisotropicTextures: 0 antiAliasing: 0 @@ -88,7 +88,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 - blendWeights: 2 + skinWeights: 2 textureQuality: 0 anisotropicTextures: 1 antiAliasing: 0 @@ -123,7 +123,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 - blendWeights: 2 + skinWeights: 2 textureQuality: 0 anisotropicTextures: 1 antiAliasing: 0 @@ -158,7 +158,7 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 - blendWeights: 4 + skinWeights: 4 textureQuality: 0 anisotropicTextures: 2 antiAliasing: 2 @@ -193,10 +193,10 @@ QualitySettings: shadowCascade2Split: 0.33333334 shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 - blendWeights: 4 + skinWeights: 4 textureQuality: 0 anisotropicTextures: 2 - antiAliasing: 2 + antiAliasing: 4 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 1c92a78..2944a8b 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -3,7 +3,8 @@ --- !u!78 &1 TagManager: serializedVersion: 2 - tags: [] + tags: + - HelpObject layers: - Default - TransparentFX

dr5h}8ISm(MjVci3$Hv$MCfB*srAbIB?qD( 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 literal 0 HcmV?d00001 diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/backgroundloading.png.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/backgroundloading.png.meta new file mode 100644 index 0000000..610b4a5 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Textures/Loading/backgroundloading.png.meta @@ -0,0 +1,103 @@ +fileFormatVersion: 2 +guid: eeda6b01fb5e81e41b007ce75ffd2511 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 10 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 16 + mipBias: -100 + wrapU: 1 + wrapV: -1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 1 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 1 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning.prefab b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning.prefab new file mode 100644 index 0000000..be92e06 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning.prefab @@ -0,0 +1,361 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1632655016766084} + m_IsPrefabParent: 1 +--- !u!1 &1230655829210014 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224751525030771116} + - component: {fileID: 222971739578382902} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1330921024155906 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224472641033034946} + - component: {fileID: 222821155271024134} + - component: {fileID: 114779677273421344} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1564682343566758 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224180898579445112} + - component: {fileID: 222850324215655790} + - component: {fileID: 114097547809574688} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1632655016766084 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224578675721850100} + - component: {fileID: 223818183227583824} + - component: {fileID: 114703164152557802} + m_Layer: 5 + m_Name: Warning + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1698585890852646 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224391173512650546} + - component: {fileID: 222650210020025450} + - component: {fileID: 114241564671057790} + - component: {fileID: 95159841045473680} + m_Layer: 5 + m_Name: Spinner + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!95 &95159841045473680 +Animator: + serializedVersion: 3 + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1698585890852646} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 318c58d8448ac1a4a919ce2484a8e4b0, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 +--- !u!114 &114097547809574688 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1564682343566758} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: afd7bbe71ea0d3b4fbbfdc3248fb0ff7, type: 2} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 21300000, guid: eeda6b01fb5e81e41b007ce75ffd2511, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 +--- !u!114 &114241564671057790 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1698585890852646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: afd7bbe71ea0d3b4fbbfdc3248fb0ff7, type: 2} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 21300000, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + m_Type: 3 + m_PreserveAspect: 1 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 2 +--- !u!114 &114703164152557802 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1632655016766084} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!114 &114779677273421344 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1330921024155906} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: afd7bbe71ea0d3b4fbbfdc3248fb0ff7, type: 2} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_FontData: + m_Font: {fileID: 12800000, guid: f0347d4b40918f74aba41da870e47183, type: 3} + m_FontSize: 48 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 1 + m_LineSpacing: 1.4 + m_Text: '... Loading ...' +--- !u!222 &222650210020025450 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1698585890852646} +--- !u!222 &222821155271024134 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1330921024155906} +--- !u!222 &222850324215655790 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1564682343566758} +--- !u!222 &222971739578382902 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1230655829210014} +--- !u!223 &223818183227583824 +Canvas: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1632655016766084} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 1 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 1 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &224180898579445112 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1564682343566758} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 0.02} + m_Children: + - {fileID: 224472641033034946} + - {fileID: 224751525030771116} + m_Father: {fileID: 224578675721850100} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 40, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224391173512650546 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1698585890852646} + m_LocalRotation: {x: 0, y: 0, z: 0.15850271, w: 0.98735857} + m_LocalPosition: {x: 0, y: 0, z: 0.661} + m_LocalScale: {x: 1, y: 1, z: 0.08} + m_Children: [] + m_Father: {fileID: 224751525030771116} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 18.24} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224472641033034946 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1330921024155906} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0.661} + m_LocalScale: {x: 0.5, y: 0.5, z: 1} + m_Children: [] + m_Father: {fileID: 224180898579445112} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.4, y: 0.15} + m_AnchorMax: {x: 0.6, y: 0.35} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224578675721850100 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1632655016766084} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 224180898579445112} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!224 &224751525030771116 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1230655829210014} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0.661} + m_LocalScale: {x: 2, y: 2, z: 0.08} + m_Children: + - {fileID: 224391173512650546} + m_Father: {fileID: 224180898579445112} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.4, y: 0.4} + m_AnchorMax: {x: 0.6, y: 0.6} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning.prefab.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning.prefab.meta new file mode 100644 index 0000000..7e4dac4 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning.prefab.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bb4588b67b8b00f45a51b88ff2294490 +timeCreated: 1501157132 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning_VR.prefab b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning_VR.prefab new file mode 100644 index 0000000..9f9db0a --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning_VR.prefab @@ -0,0 +1,361 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 1632655016766084} + m_IsPrefabParent: 1 +--- !u!1 &1230655829210014 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224751525030771116} + - component: {fileID: 222971739578382902} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1330921024155906 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224472641033034946} + - component: {fileID: 222821155271024134} + - component: {fileID: 114779677273421344} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1564682343566758 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224180898579445112} + - component: {fileID: 222850324215655790} + - component: {fileID: 114097547809574688} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1632655016766084 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224578675721850100} + - component: {fileID: 223818183227583824} + - component: {fileID: 114703164152557802} + m_Layer: 5 + m_Name: Warning_VR + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!1 &1698585890852646 +GameObject: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 5 + m_Component: + - component: {fileID: 224391173512650546} + - component: {fileID: 222650210020025450} + - component: {fileID: 114241564671057790} + - component: {fileID: 95159841045473680} + m_Layer: 5 + m_Name: Spinner + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!95 &95159841045473680 +Animator: + serializedVersion: 3 + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1698585890852646} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 318c58d8448ac1a4a919ce2484a8e4b0, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 +--- !u!114 &114097547809574688 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1564682343566758} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: afd7bbe71ea0d3b4fbbfdc3248fb0ff7, type: 2} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 21300000, guid: eeda6b01fb5e81e41b007ce75ffd2511, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 +--- !u!114 &114241564671057790 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1698585890852646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: afd7bbe71ea0d3b4fbbfdc3248fb0ff7, type: 2} + m_Color: {r: 0.63235295, g: 0.63235295, b: 0.63235295, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_Sprite: {fileID: 21300000, guid: d111b0c81cf4e2c40b16a56e3a89bd79, type: 3} + m_Type: 3 + m_PreserveAspect: 1 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 2 +--- !u!114 &114703164152557802 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1632655016766084} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 0.1 +--- !u!114 &114779677273421344 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1330921024155906} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 2100000, guid: afd7bbe71ea0d3b4fbbfdc3248fb0ff7, type: 2} + m_Color: {r: 0.6838235, g: 0.6838235, b: 0.6838235, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_FontData: + m_Font: {fileID: 12800000, guid: f0347d4b40918f74aba41da870e47183, type: 3} + m_FontSize: 48 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 300 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 1 + m_LineSpacing: 1.4 + m_Text: '... Loading ...' +--- !u!222 &222650210020025450 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1698585890852646} +--- !u!222 &222821155271024134 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1330921024155906} +--- !u!222 &222850324215655790 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1564682343566758} +--- !u!222 &222971739578382902 +CanvasRenderer: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1230655829210014} +--- !u!223 &223818183227583824 +Canvas: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1632655016766084} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 1 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 1 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &224180898579445112 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1564682343566758} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 0.02} + m_Children: + - {fileID: 224472641033034946} + - {fileID: 224751525030771116} + m_Father: {fileID: 224578675721850100} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 40, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224391173512650546 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1698585890852646} + m_LocalRotation: {x: 0, y: 0, z: 0.15850271, w: 0.98735857} + m_LocalPosition: {x: 0, y: 0, z: 0.661} + m_LocalScale: {x: 1, y: 1, z: 0.08} + m_Children: [] + m_Father: {fileID: 224751525030771116} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 18.24} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224472641033034946 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1330921024155906} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0.661} + m_LocalScale: {x: 0.5, y: 0.5, z: 1} + m_Children: [] + m_Father: {fileID: 224180898579445112} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.4, y: 0.15} + m_AnchorMax: {x: 0.6, y: 0.35} + m_AnchoredPosition: {x: 0, y: 87} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!224 &224578675721850100 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1632655016766084} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 224180898579445112} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!224 &224751525030771116 +RectTransform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 1230655829210014} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0.661} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 224391173512650546} + m_Father: {fileID: 224180898579445112} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.4, y: 0.4} + m_AnchorMax: {x: 0.6, y: 0.6} + m_AnchoredPosition: {x: 0, y: 23} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning_VR.prefab.meta b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning_VR.prefab.meta new file mode 100644 index 0000000..d67537d --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Resources/PrefabsUI/Warning_VR.prefab.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3a45ae540ff8e0b44867ebc77430bdbe +timeCreated: 1501157132 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 100100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts.meta b/Assets/ZED/SDK/Helpers/Scripts.meta new file mode 100644 index 0000000..1481c19 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5841422768f606444a742b8328e71175 +folderAsset: yes +timeCreated: 1507732750 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display.meta b/Assets/ZED/SDK/Helpers/Scripts/Display.meta new file mode 100644 index 0000000..8184191 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bd940c2d715c2d94591d7783dd933c31 +folderAsset: yes +timeCreated: 1507561215 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ZED/SDK/Helpers/Scripts/Display/HideFromWrongCameras.cs b/Assets/ZED/SDK/Helpers/Scripts/Display/HideFromWrongCameras.cs new file mode 100644 index 0000000..a46fca3 --- /dev/null +++ b/Assets/ZED/SDK/Helpers/Scripts/Display/HideFromWrongCameras.cs @@ -0,0 +1,120 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +///