Browse Source

UVC Camera

slambb 2 years ago
parent
commit
9750aba456
100 changed files with 10984 additions and 0 deletions
  1. 8 0
      Assets/UVC4UnityAndroidPlugin.meta
  2. 8 0
      Assets/UVC4UnityAndroidPlugin/Editor.meta
  3. 21 0
      Assets/UVC4UnityAndroidPlugin/Editor/ComponentRestrictionDrawer.cs
  4. 11 0
      Assets/UVC4UnityAndroidPlugin/Editor/ComponentRestrictionDrawer.cs.meta
  5. 202 0
      Assets/UVC4UnityAndroidPlugin/LICENSE
  6. 7 0
      Assets/UVC4UnityAndroidPlugin/LICENSE.meta
  7. 8 0
      Assets/UVC4UnityAndroidPlugin/Prefabs.meta
  8. 63 0
      Assets/UVC4UnityAndroidPlugin/Prefabs/CameraDrawer.prefab
  9. 7 0
      Assets/UVC4UnityAndroidPlugin/Prefabs/CameraDrawer.prefab.meta
  10. 80 0
      Assets/UVC4UnityAndroidPlugin/Prefabs/UVCDrawer.prefab
  11. 7 0
      Assets/UVC4UnityAndroidPlugin/Prefabs/UVCDrawer.prefab.meta
  12. 85 0
      Assets/UVC4UnityAndroidPlugin/README.md
  13. 7 0
      Assets/UVC4UnityAndroidPlugin/README.md.meta
  14. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples.meta
  15. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples/Materials.meta
  16. 81 0
      Assets/UVC4UnityAndroidPlugin/Samples/Materials/EquirectangularStichTexture.mat
  17. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples/Materials/EquirectangularStichTexture.mat.meta
  18. 77 0
      Assets/UVC4UnityAndroidPlugin/Samples/Materials/PassThroughTexture.mat
  19. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples/Materials/PassThroughTexture.mat.meta
  20. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes.meta
  21. 599 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaS1080pScene.unity
  22. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaS1080pScene.unity.meta
  23. 599 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaSScene.unity
  24. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaSScene.unity.meta
  25. 63 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaSSceneSettings.lighting
  26. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaSSceneSettings.lighting.meta
  27. 659 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaVScene.unity
  28. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaVScene.unity.meta
  29. 659 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaZ1Scene.unity
  30. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaZ1Scene.unity.meta
  31. 729 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2DScene.unity
  32. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2DScene.unity.meta
  33. 733 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2Dx2Scene.unity
  34. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2Dx2Scene.unity.meta
  35. 687 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC3DScene.unity
  36. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC3DScene.unity.meta
  37. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scripts.meta
  38. 73 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scripts/CameraController.cs
  39. 11 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scripts/CameraController.cs.meta
  40. 74 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scripts/CubeHandler.cs
  41. 11 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scripts/CubeHandler.cs.meta
  42. 130 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scripts/TouchEventManager.cs
  43. 11 0
      Assets/UVC4UnityAndroidPlugin/Samples/Scripts/TouchEventManager.cs.meta
  44. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples/Shaders.meta
  45. 6 0
      Assets/UVC4UnityAndroidPlugin/Samples/Shaders/README.md
  46. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Shaders/README.md.meta
  47. 219 0
      Assets/UVC4UnityAndroidPlugin/Samples/Shaders/ThetaRealtimeEquirectangular1080p.shader
  48. 9 0
      Assets/UVC4UnityAndroidPlugin/Samples/Shaders/ThetaRealtimeEquirectangular1080p.shader.meta
  49. 8 0
      Assets/UVC4UnityAndroidPlugin/Samples/Spheres.meta
  50. 3 0
      Assets/UVC4UnityAndroidPlugin/Samples/Spheres/README.md
  51. 7 0
      Assets/UVC4UnityAndroidPlugin/Samples/Spheres/README.md.meta
  52. BIN
      Assets/UVC4UnityAndroidPlugin/Samples/Spheres/Sphere100.fbx
  53. 97 0
      Assets/UVC4UnityAndroidPlugin/Samples/Spheres/Sphere100.fbx.meta
  54. 8 0
      Assets/UVC4UnityAndroidPlugin/Scripts.meta
  55. 334 0
      Assets/UVC4UnityAndroidPlugin/Scripts/AndroidUtils.cs
  56. 11 0
      Assets/UVC4UnityAndroidPlugin/Scripts/AndroidUtils.cs.meta
  57. 17 0
      Assets/UVC4UnityAndroidPlugin/Scripts/ComponentRestrictionAttribute.cs
  58. 11 0
      Assets/UVC4UnityAndroidPlugin/Scripts/ComponentRestrictionAttribute.cs.meta
  59. 58 0
      Assets/UVC4UnityAndroidPlugin/Scripts/Debug.cs
  60. 11 0
      Assets/UVC4UnityAndroidPlugin/Scripts/Debug.cs.meta
  61. 51 0
      Assets/UVC4UnityAndroidPlugin/Scripts/IUVCDrawer.cs
  62. 11 0
      Assets/UVC4UnityAndroidPlugin/Scripts/IUVCDrawer.cs.meta
  63. 139 0
      Assets/UVC4UnityAndroidPlugin/Scripts/UVCDevice.cs
  64. 11 0
      Assets/UVC4UnityAndroidPlugin/Scripts/UVCDevice.cs.meta
  65. 387 0
      Assets/UVC4UnityAndroidPlugin/Scripts/UVCDrawer.cs
  66. 11 0
      Assets/UVC4UnityAndroidPlugin/Scripts/UVCDrawer.cs.meta
  67. 132 0
      Assets/UVC4UnityAndroidPlugin/Scripts/UVCFilter.cs
  68. 11 0
      Assets/UVC4UnityAndroidPlugin/Scripts/UVCFilter.cs.meta
  69. 813 0
      Assets/UVC4UnityAndroidPlugin/Scripts/UVCManager.cs
  70. 11 0
      Assets/UVC4UnityAndroidPlugin/Scripts/UVCManager.cs.meta
  71. 8 0
      Assets/WebCamera.meta
  72. 8 0
      Assets/WebCamera/Image.meta
  73. BIN
      Assets/WebCamera/Image/crosshair2.png
  74. 123 0
      Assets/WebCamera/Image/crosshair2.png.meta
  75. 8 0
      Assets/WebCamera/Script.meta
  76. 8 0
      Assets/WebCamera/Script/ZIM.meta
  77. 8 0
      Assets/WebCamera/Script/ZIM/InfraredLocate.meta
  78. 732 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredLocate.cs
  79. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredLocate.cs.meta
  80. 8 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot.meta
  81. 156 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpot.cs
  82. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpot.cs.meta
  83. 15 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpotSettings.asset
  84. 8 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpotSettings.asset.meta
  85. 31 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpotSettings.cs
  86. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpotSettings.cs.meta
  87. 131 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelArea.cs
  88. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelArea.cs.meta
  89. 99 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelCircleArea.cs
  90. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelCircleArea.cs.meta
  91. 214 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelSpotArea.cs
  92. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelSpotArea.cs.meta
  93. 275 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/PerspectiveTransform.cs
  94. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/PerspectiveTransform.cs.meta
  95. 690 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/ScreenIdentification.cs
  96. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/ScreenIdentification.cs.meta
  97. 72 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/ScreenMap.cs
  98. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/ScreenMap.cs.meta
  99. 74 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/SimpleLocationEstimation.cs
  100. 11 0
      Assets/WebCamera/Script/ZIM/InfraredLocate/SimpleLocationEstimation.cs.meta

+ 8 - 0
Assets/UVC4UnityAndroidPlugin.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dc42c60a53b09ac42b0449859a0baaa7
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Editor.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 341de77d50436cd49bd7b6bfde721d6e
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 21 - 0
Assets/UVC4UnityAndroidPlugin/Editor/ComponentRestrictionDrawer.cs

@@ -0,0 +1,21 @@
+using UnityEngine;
+using UnityEditor;
+
+[CustomPropertyDrawer(typeof(ComponentRestrictionAttribute))]
+public class ComponentRestrictionDrawer : PropertyDrawer
+{
+	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+	{
+		var restriction = (ComponentRestrictionAttribute)attribute;
+
+		if (property.propertyType == SerializedPropertyType.ObjectReference)
+		{
+			EditorGUI.ObjectField(position, property, restriction.type);
+		}
+		else
+		{
+			EditorGUI.PropertyField(position, property);
+		}
+	}
+
+} // class ComponentRestrictionDrawer

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Editor/ComponentRestrictionDrawer.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9169d1076e4b0574f9af3c20bc50ad2f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 202 - 0
Assets/UVC4UnityAndroidPlugin/LICENSE

@@ -0,0 +1,202 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/LICENSE.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 1e2909481c2778a47a3806bf0425bf12
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Prefabs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c17e7aaf853723545bf653dcbb93d635
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 63 - 0
Assets/UVC4UnityAndroidPlugin/Prefabs/CameraDrawer.prefab

@@ -0,0 +1,63 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &6465409448752295666
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6465409448752295679}
+  - component: {fileID: 114619053125224756}
+  - component: {fileID: 5777022740684865818}
+  m_Layer: 0
+  m_Name: CameraDrawer
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 4294967295
+  m_IsActive: 1
+--- !u!4 &6465409448752295679
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6465409448752295666}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &114619053125224756
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6465409448752295666}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 6eca0239a3e830b45b761684e2a8c8ca, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+--- !u!114 &5777022740684865818
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6465409448752295666}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: bda887b4b2b31454fb7dd4b9cf6982cb, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  DefaultWidth: 1280
+  DefaultHeight: 720
+  PreferH264: 1
+  DisableUVC: 0
+  CameraRenderSettings: []

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Prefabs/CameraDrawer.prefab.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ff17b3cd9f54c334da5368453f56b8e8
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 80 - 0
Assets/UVC4UnityAndroidPlugin/Prefabs/UVCDrawer.prefab

@@ -0,0 +1,80 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &7953172909807438327
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6011951749156047501}
+  - component: {fileID: 5454767711725787237}
+  - component: {fileID: 7716261784260357304}
+  - component: {fileID: 464229095961303548}
+  m_Layer: 0
+  m_Name: UVCDrawer
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &6011951749156047501
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7953172909807438327}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &5454767711725787237
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7953172909807438327}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 6eca0239a3e830b45b761684e2a8c8ca, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+--- !u!114 &7716261784260357304
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7953172909807438327}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: f7e3fa0f7bdc68444abad301469f7cf7, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  DefaultWidth: 1280
+  DefaultHeight: 720
+  PreferH264: 0
+  UVCDrawers: []
+--- !u!114 &464229095961303548
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7953172909807438327}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: efb1bc18f15fa0546b998062ea4861a3, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  DefaultWidth: 1280
+  DefaultHeight: 720
+  UVCFilters: []
+  RenderTargets:
+  - {fileID: 0}

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Prefabs/UVCDrawer.prefab.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: fa65cd0b0e2ffad4180eabf8fe755f9a
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 85 - 0
Assets/UVC4UnityAndroidPlugin/README.md

@@ -0,0 +1,85 @@
+# UVC4UnityAndroid
+
+
+Plugin project and samples to access UVC devices on Unity Android.
+
+Copyright (c) 2014-2022 saki t_saki@serenegiant.com
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+All files in the folder are under this Apache License, Version 2.0.   
+Files under `UVC4UnityAndroid/Assets/UVC4UnityAndroidPlugin/Samples/` may have different license. Please read README.md in those folders well.
+
+
+## Features:
+
+* Supports UVC 1.0/1.1 and 1.5 devices (Most of UVC devices are UVC1.1).
+* Supports `armeabi-v7a`, `arm64-v8a`, `x86` and `x86_64` architectures.  
+  `arm64-v8a`, `x86` and `x86_64` require IL2CPP.
+* Supports H.264, MJPEG and YUV and automatically decode video images into Texture of Unity. Please see sample scenes in Samples folder.   
+   You can get H.264 stream from Ricoh THETA S(1920x1080@H.264,30fps, dual fisheye video images) and THETA V(3840x1920@H.264,30fps, equirectangular video images), THETA Z1(3840x1920@H.264,30fps, equirectangular video images), Logitech C920, C922, C930e etc.
+* Supports multiple UVC devices at the same time(Although frame rate, number of UVC devices and video size will be limited by bandwidth and power supply of USB.)
+* Supports both isochronous and bulk transfer.
+* Supports USB2 and USB3(experimental). Unfortunately USB3 on many devices still have issues, especially when using isochronous transfer.
+* Support changing video size.
+
+## Limitations:  
+
+* Apk with target API level 28 and more will not work well on Android 10 devices because of issues on Android 10 itself (Many devices of Android 10 and later were already solved this issues but you may come across this issues).
+  Please see details about this on [Issue Tracker of Google](https://issuetracker.google.com/issues/145082934) and [My Blog](https://serenegiant.com/blog/?p=3696).
+* This project is still in progress and some features are not available now. Ex. Controlling UVC devices is not implemented yet. Ex. controlling contrast, brightness, shutter condition etc. do not work yet.
+* You can get video images only from UVC devices, some devices like EasyCap are not UVC device and can't get from them. Internal cameras on Android devices also are not supported.
+* Backend libraries support UBS3, but USB3 on Android devices are still unstable and it may not work well. In that case please connect your UVC devices over USB2.
+* This plugin can work on only real Android devices, can't work on editor of Unity and on `Unity Remote`
+* User may need to touch app screen after giving USB permission on some Android devices by limitation os Android OS itself.
+* Streaming with H.264 needs Android 8 and later devices (required API>=26 but API>=29 will be better for performance)
+* Android system never send attach event for THETA V and THETA Z1(becauseof issues on Android system itself), as a result app can never start automatically. Please launch app by manually.
+* Be sure to confirm THETA V and Z1 is in `live streaming` mode. THETA V and Z1 will report `USB Image Class` when they are in `camera mode` or `video mode` and app will detecte it. But this `USB Image Class` is not av `UVC(USB Video Class)` and have no video control interface and video control interface and can't get video images from it. 
+* Currently only supports OpenGL|ES as Graphic API. Vulkan is not supported now. If you can't see video images, please confirm settings of Graphic API on player settings.
+
+## Dependancies:
+
+* This plugin uses `System.Text.Json`(and related packages) from Microsoft to parse JSON. You can install the package using `NuGet`(You can use [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity/releases))  
+  If you need to use other package like `Json.NET` to parse json, you can use it with some modification.  
+
+
+## How to use:
+
+1. Create new project / open existing project by Unity.
+2. Install `System.Text.Json` if you don't yet.
+   1. Install 'NuGet'([NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity/releases)).
+   2. Select `Manage NuGet Packages` from `NuGet` menu.
+   3. Search `System.Text.Json` from search box.
+   4. Select `System.Text.Json` and install it.
+3. Import release package of `UVC4UnityAndroid`
+4. Confirm Graphic API setting on player settings, only OpenGL|ES is supported.
+5. Open one of sample scene from `UVC4UnityAndroid/Samples/Scenes` folder.
+6. Build and run apk on your real Android device.
+7. Connect UVC device(s) with Android Device. Some UVC devices / some Android devices may need powered USB hub between UVC device and Android device.
+
+## Note:
+
+* The plugin project is for Unity 2020.3.36f1 now and may need modification on other Unity version.
+* This plugin setup `AndroidManifest.xml` to be able to keep permanent permission for UVC device(s).
+   If you don't want this behavior, please remove following steps. The user need to give permission everytime they connect UVC device(s).
+   1. Export your project as project of Android Studio from `Build Settings` window.
+   2. Open the exported project with Android Studio.
+   3. Open `AndroidManifest.xml` under `{project root}/src/main`
+   4. Add `<activity android:name="com.serenegiant.uvcplugin.UsbPermissionActivity" tools:node="remove"/>` in `Application` section.
+   5. Build apk with Android Studio.
+
+## Release Note:
+
+* r0.1.0 on 24 Dec. 2019
+   * First release.
+* r0.2.0 on 3 July. 2022

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/README.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 7779bcbdd4d240546b62792fa70ab1a2
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d92e973753811234782a70bb2bb1b10c
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Materials.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0bb3c7181f79acf4f86a028064f15f4b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 81 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Materials/EquirectangularStichTexture.mat

@@ -0,0 +1,81 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: EquirectangularStichTexture
+  m_Shader: {fileID: 4800000, guid: 91b8677abe2e60d48a8941053cf517ff, type: 3}
+  m_ShaderKeywords: _DRAW_BOTH _MODE_THETA_S
+  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
+    - _Draw: 0
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 1
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _Radius: 0.445
+    - _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}
+    - _UVOffset: {r: 0, g: 0, b: 0, a: 0}
+  m_BuildTextureStacks: []

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Materials/EquirectangularStichTexture.mat.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 07c806f4a3eb403418fed4fe84d32115
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 2100000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 77 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Materials/PassThroughTexture.mat

@@ -0,0 +1,77 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: PassThroughTexture
+  m_Shader: {fileID: 10752, guid: 0000000000000000f000000000000000, type: 0}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Materials/PassThroughTexture.mat.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 280f2e40f1de1d940976f143e80c6030
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 2100000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4721287dd6c098d44b98a9ff73dd30b9
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 599 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaS1080pScene.unity

@@ -0,0 +1,599 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641258, b: 0.5748172, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 12
+  m_GIWorkflowMode: 0
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 1
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    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_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_LightingSettings: {fileID: 4890085278179872738, guid: a2735a6978946c84993875639c8a1ab2,
+    type: 2}
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    maxJobWorkers: 0
+    preserveTilesOutsideBounds: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &148948003
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 148948005}
+  - component: {fileID: 148948004}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &148948004
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 148948003}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  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
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    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}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  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_UseViewFrustumForShadowCasterCull: 1
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &148948005
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 148948003}
+  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!1001 &278355116
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 1920
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 1080
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1098241171}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1098241171}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_RootOrder
+      value: 3
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: PreferH264
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 1920
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 1080
+      objectReference: {fileID: 0}
+    - target: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_Name
+      value: UVCDrawer
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: fa65cd0b0e2ffad4180eabf8fe755f9a, type: 3}
+--- !u!1 &1052051898
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1052051901}
+  - component: {fileID: 1052051900}
+  - component: {fileID: 1052051899}
+  - component: {fileID: 1052051902}
+  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 &1052051899
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  m_Enabled: 1
+--- !u!20 &1052051900
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  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_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  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 &1052051901
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1052051902
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0c32ee072b65f5346ac9f54c8bf3f80c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  TargetCamera: {fileID: 0}
+--- !u!1 &1098241171 stripped
+GameObject:
+  m_CorrespondingSourceObject: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4,
+    type: 3}
+  m_PrefabInstance: {fileID: 1109588832}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &1109588832
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_Name
+      value: Sphere100
+      objectReference: {fileID: 0}
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_IsActive
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_StaticEditorFlags
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_RootOrder
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_CastShadows
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_ReceiveShadows
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LightProbeUsage
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_ReflectionProbeUsage
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_Materials.Array.data[0]
+      value: 
+      objectReference: {fileID: 2100000, guid: 07c806f4a3eb403418fed4fe84d32115, type: 2}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+--- !u!1 &1395363809
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1395363812}
+  - component: {fileID: 1395363811}
+  - component: {fileID: 1395363810}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 4294967295
+  m_IsActive: 1
+--- !u!114 &1395363810
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &1395363811
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &1395363812
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaS1080pScene.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 3e6d87784cae8c94788533a2d77f733f
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 599 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaSScene.unity

@@ -0,0 +1,599 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641258, b: 0.5748172, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 12
+  m_GIWorkflowMode: 0
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 1
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    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_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_LightingSettings: {fileID: 4890085278179872738, guid: a2735a6978946c84993875639c8a1ab2,
+    type: 2}
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    maxJobWorkers: 0
+    preserveTilesOutsideBounds: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &148948003
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 148948005}
+  - component: {fileID: 148948004}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &148948004
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 148948003}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  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
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    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}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  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_UseViewFrustumForShadowCasterCull: 1
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &148948005
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 148948003}
+  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!1001 &278355116
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 1280
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 720
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1098241171}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1098241171}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_RootOrder
+      value: 3
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: PreferH264
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 1280
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 720
+      objectReference: {fileID: 0}
+    - target: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_Name
+      value: UVCDrawer
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: fa65cd0b0e2ffad4180eabf8fe755f9a, type: 3}
+--- !u!1 &1052051898
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1052051901}
+  - component: {fileID: 1052051900}
+  - component: {fileID: 1052051899}
+  - component: {fileID: 1052051902}
+  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 &1052051899
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  m_Enabled: 1
+--- !u!20 &1052051900
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  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_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  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 &1052051901
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1052051902
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0c32ee072b65f5346ac9f54c8bf3f80c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  TargetCamera: {fileID: 0}
+--- !u!1 &1098241171 stripped
+GameObject:
+  m_CorrespondingSourceObject: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4,
+    type: 3}
+  m_PrefabInstance: {fileID: 1109588832}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &1109588832
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_Name
+      value: Sphere100
+      objectReference: {fileID: 0}
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_IsActive
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_StaticEditorFlags
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_RootOrder
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_CastShadows
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_ReceiveShadows
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LightProbeUsage
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_ReflectionProbeUsage
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_Materials.Array.data[0]
+      value: 
+      objectReference: {fileID: 2100000, guid: 07c806f4a3eb403418fed4fe84d32115, type: 2}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+--- !u!1 &1395363809
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1395363812}
+  - component: {fileID: 1395363811}
+  - component: {fileID: 1395363810}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 4294967295
+  m_IsActive: 1
+--- !u!114 &1395363810
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &1395363811
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &1395363812
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaSScene.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8912afb67f655ac448848e33282d23f6
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 63 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaSSceneSettings.lighting

@@ -0,0 +1,63 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!850595691 &4890085278179872738
+LightingSettings:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: ThetaSSceneSettings
+  serializedVersion: 3
+  m_GIWorkflowMode: 0
+  m_EnableBakedLightmaps: 1
+  m_EnableRealtimeLightmaps: 1
+  m_RealtimeEnvironmentLighting: 1
+  m_BounceScale: 1
+  m_AlbedoBoost: 1
+  m_IndirectOutputScale: 1
+  m_UsingShadowmask: 1
+  m_BakeBackend: 1
+  m_LightmapMaxSize: 1024
+  m_BakeResolution: 40
+  m_Padding: 2
+  m_TextureCompression: 1
+  m_AO: 0
+  m_AOMaxDistance: 1
+  m_CompAOExponent: 1
+  m_CompAOExponentDirect: 0
+  m_ExtractAO: 0
+  m_MixedBakeMode: 2
+  m_LightmapsBakeMode: 1
+  m_FilterMode: 1
+  m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
+  m_ExportTrainingData: 0
+  m_TrainingDataDestination: TrainingData
+  m_RealtimeResolution: 2
+  m_ForceWhiteAlbedo: 0
+  m_ForceUpdates: 0
+  m_FinalGather: 0
+  m_FinalGatherRayCount: 256
+  m_FinalGatherFiltering: 1
+  m_PVRCulling: 1
+  m_PVRSampling: 1
+  m_PVRDirectSampleCount: 32
+  m_PVRSampleCount: 500
+  m_PVREnvironmentSampleCount: 500
+  m_PVREnvironmentReferencePointCount: 2048
+  m_LightProbeSampleCountMultiplier: 4
+  m_PVRBounces: 2
+  m_PVRMinBounces: 2
+  m_PVREnvironmentMIS: 0
+  m_PVRFilteringMode: 2
+  m_PVRDenoiserTypeDirect: 0
+  m_PVRDenoiserTypeIndirect: 0
+  m_PVRDenoiserTypeAO: 0
+  m_PVRFilterTypeDirect: 0
+  m_PVRFilterTypeIndirect: 0
+  m_PVRFilterTypeAO: 0
+  m_PVRFilteringGaussRadiusDirect: 1
+  m_PVRFilteringGaussRadiusIndirect: 5
+  m_PVRFilteringGaussRadiusAO: 2
+  m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+  m_PVRFilteringAtrousPositionSigmaIndirect: 2
+  m_PVRFilteringAtrousPositionSigmaAO: 1

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaSSceneSettings.lighting.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a2735a6978946c84993875639c8a1ab2
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 4890085278179872738
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 659 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaVScene.unity

@@ -0,0 +1,659 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641258, b: 0.5748172, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 12
+  m_GIWorkflowMode: 0
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 1
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    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_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_LightingSettings: {fileID: 1148448307}
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    maxJobWorkers: 0
+    preserveTilesOutsideBounds: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &148948003
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 148948005}
+  - component: {fileID: 148948004}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &148948004
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 148948003}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  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
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    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}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  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_UseViewFrustumForShadowCasterCull: 1
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &148948005
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 148948003}
+  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 &1052051898
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1052051901}
+  - component: {fileID: 1052051900}
+  - component: {fileID: 1052051899}
+  - component: {fileID: 1052051902}
+  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 &1052051899
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  m_Enabled: 1
+--- !u!20 &1052051900
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  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_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  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 &1052051901
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1052051902
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0c32ee072b65f5346ac9f54c8bf3f80c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  TargetCamera: {fileID: 0}
+--- !u!1001 &1061757389
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 3840
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 1920
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1098241171}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1098241171}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_RootOrder
+      value: 3
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: PreferH264
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 3840
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 1920
+      objectReference: {fileID: 0}
+    - target: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_Name
+      value: UVCDrawer
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: fa65cd0b0e2ffad4180eabf8fe755f9a, type: 3}
+--- !u!1 &1098241171 stripped
+GameObject:
+  m_CorrespondingSourceObject: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4,
+    type: 3}
+  m_PrefabInstance: {fileID: 1109588832}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &1109588832
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_Name
+      value: Sphere100
+      objectReference: {fileID: 0}
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_IsActive
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_StaticEditorFlags
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_RootOrder
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_CastShadows
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_ReceiveShadows
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LightProbeUsage
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_ReflectionProbeUsage
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_Materials.Array.data[0]
+      value: 
+      objectReference: {fileID: 2100000, guid: 280f2e40f1de1d940976f143e80c6030, type: 2}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+--- !u!850595691 &1148448307
+LightingSettings:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: Settings.lighting
+  serializedVersion: 3
+  m_GIWorkflowMode: 0
+  m_EnableBakedLightmaps: 1
+  m_EnableRealtimeLightmaps: 1
+  m_RealtimeEnvironmentLighting: 1
+  m_BounceScale: 1
+  m_AlbedoBoost: 1
+  m_IndirectOutputScale: 1
+  m_UsingShadowmask: 1
+  m_BakeBackend: 1
+  m_LightmapMaxSize: 1024
+  m_BakeResolution: 40
+  m_Padding: 2
+  m_TextureCompression: 1
+  m_AO: 0
+  m_AOMaxDistance: 1
+  m_CompAOExponent: 1
+  m_CompAOExponentDirect: 0
+  m_ExtractAO: 0
+  m_MixedBakeMode: 2
+  m_LightmapsBakeMode: 1
+  m_FilterMode: 1
+  m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
+  m_ExportTrainingData: 0
+  m_TrainingDataDestination: TrainingData
+  m_RealtimeResolution: 2
+  m_ForceWhiteAlbedo: 0
+  m_ForceUpdates: 0
+  m_FinalGather: 0
+  m_FinalGatherRayCount: 256
+  m_FinalGatherFiltering: 1
+  m_PVRCulling: 1
+  m_PVRSampling: 1
+  m_PVRDirectSampleCount: 32
+  m_PVRSampleCount: 500
+  m_PVREnvironmentSampleCount: 500
+  m_PVREnvironmentReferencePointCount: 2048
+  m_LightProbeSampleCountMultiplier: 4
+  m_PVRBounces: 2
+  m_PVRMinBounces: 2
+  m_PVREnvironmentMIS: 0
+  m_PVRFilteringMode: 2
+  m_PVRDenoiserTypeDirect: 0
+  m_PVRDenoiserTypeIndirect: 0
+  m_PVRDenoiserTypeAO: 0
+  m_PVRFilterTypeDirect: 0
+  m_PVRFilterTypeIndirect: 0
+  m_PVRFilterTypeAO: 0
+  m_PVRFilteringGaussRadiusDirect: 1
+  m_PVRFilteringGaussRadiusIndirect: 5
+  m_PVRFilteringGaussRadiusAO: 2
+  m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+  m_PVRFilteringAtrousPositionSigmaIndirect: 2
+  m_PVRFilteringAtrousPositionSigmaAO: 1
+--- !u!1 &1395363809
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1395363812}
+  - component: {fileID: 1395363811}
+  - component: {fileID: 1395363810}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 4294967295
+  m_IsActive: 1
+--- !u!114 &1395363810
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &1395363811
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &1395363812
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaVScene.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 428ccd87848a9894b8338e6564451bc5
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 659 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaZ1Scene.unity

@@ -0,0 +1,659 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641258, b: 0.5748172, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 12
+  m_GIWorkflowMode: 0
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 1
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    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_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_LightingSettings: {fileID: 1148448307}
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    maxJobWorkers: 0
+    preserveTilesOutsideBounds: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &148948003
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 148948005}
+  - component: {fileID: 148948004}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &148948004
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 148948003}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  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
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    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}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  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_UseViewFrustumForShadowCasterCull: 1
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &148948005
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 148948003}
+  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 &1052051898
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1052051901}
+  - component: {fileID: 1052051900}
+  - component: {fileID: 1052051899}
+  - component: {fileID: 1052051902}
+  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 &1052051899
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  m_Enabled: 1
+--- !u!20 &1052051900
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  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_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  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 &1052051901
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1052051902
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1052051898}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0c32ee072b65f5346ac9f54c8bf3f80c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  TargetCamera: {fileID: 0}
+--- !u!1001 &1061757389
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 3840
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 1920
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1098241171}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1098241171}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_RootOrder
+      value: 3
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: PreferH264
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 3840
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 1920
+      objectReference: {fileID: 0}
+    - target: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_Name
+      value: UVCDrawer
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: fa65cd0b0e2ffad4180eabf8fe755f9a, type: 3}
+--- !u!1 &1098241171 stripped
+GameObject:
+  m_CorrespondingSourceObject: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4,
+    type: 3}
+  m_PrefabInstance: {fileID: 1109588832}
+  m_PrefabAsset: {fileID: 0}
+--- !u!1001 &1109588832
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_Name
+      value: Sphere100
+      objectReference: {fileID: 0}
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_IsActive
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_StaticEditorFlags
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_RootOrder
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.x
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.y
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalScale.z
+      value: 100
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 400000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_CastShadows
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_ReceiveShadows
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_LightProbeUsage
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_ReflectionProbeUsage
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 2300000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+      propertyPath: m_Materials.Array.data[0]
+      value: 
+      objectReference: {fileID: 2100000, guid: 280f2e40f1de1d940976f143e80c6030, type: 2}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 368d458452cb14c439840c35167fa7b4, type: 3}
+--- !u!850595691 &1148448307
+LightingSettings:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: Settings.lighting
+  serializedVersion: 3
+  m_GIWorkflowMode: 0
+  m_EnableBakedLightmaps: 1
+  m_EnableRealtimeLightmaps: 1
+  m_RealtimeEnvironmentLighting: 1
+  m_BounceScale: 1
+  m_AlbedoBoost: 1
+  m_IndirectOutputScale: 1
+  m_UsingShadowmask: 1
+  m_BakeBackend: 1
+  m_LightmapMaxSize: 1024
+  m_BakeResolution: 40
+  m_Padding: 2
+  m_TextureCompression: 1
+  m_AO: 0
+  m_AOMaxDistance: 1
+  m_CompAOExponent: 1
+  m_CompAOExponentDirect: 0
+  m_ExtractAO: 0
+  m_MixedBakeMode: 2
+  m_LightmapsBakeMode: 1
+  m_FilterMode: 1
+  m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
+  m_ExportTrainingData: 0
+  m_TrainingDataDestination: TrainingData
+  m_RealtimeResolution: 2
+  m_ForceWhiteAlbedo: 0
+  m_ForceUpdates: 0
+  m_FinalGather: 0
+  m_FinalGatherRayCount: 256
+  m_FinalGatherFiltering: 1
+  m_PVRCulling: 1
+  m_PVRSampling: 1
+  m_PVRDirectSampleCount: 32
+  m_PVRSampleCount: 500
+  m_PVREnvironmentSampleCount: 500
+  m_PVREnvironmentReferencePointCount: 2048
+  m_LightProbeSampleCountMultiplier: 4
+  m_PVRBounces: 2
+  m_PVRMinBounces: 2
+  m_PVREnvironmentMIS: 0
+  m_PVRFilteringMode: 2
+  m_PVRDenoiserTypeDirect: 0
+  m_PVRDenoiserTypeIndirect: 0
+  m_PVRDenoiserTypeAO: 0
+  m_PVRFilterTypeDirect: 0
+  m_PVRFilterTypeIndirect: 0
+  m_PVRFilterTypeAO: 0
+  m_PVRFilteringGaussRadiusDirect: 1
+  m_PVRFilteringGaussRadiusIndirect: 5
+  m_PVRFilteringGaussRadiusAO: 2
+  m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+  m_PVRFilteringAtrousPositionSigmaIndirect: 2
+  m_PVRFilteringAtrousPositionSigmaAO: 1
+--- !u!1 &1395363809
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1395363812}
+  - component: {fileID: 1395363811}
+  - component: {fileID: 1395363810}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 4294967295
+  m_IsActive: 1
+--- !u!114 &1395363810
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &1395363811
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &1395363812
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1395363809}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/ThetaZ1Scene.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ff3c74b77a7823147b9544bb43b1ce56
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 729 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2DScene.unity

@@ -0,0 +1,729 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748171, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 12
+  m_GIWorkflowMode: 0
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 1
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    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_PVREnvironmentMIS: 0
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_LightingSettings: {fileID: 727450338}
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    maxJobWorkers: 0
+    preserveTilesOutsideBounds: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &548459541
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 548459543}
+  - component: {fileID: 548459542}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &548459542
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 548459541}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  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
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    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}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  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_UseViewFrustumForShadowCasterCull: 1
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &548459543
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 548459541}
+  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!850595691 &727450338
+LightingSettings:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_Name: Settings.lighting
+  serializedVersion: 3
+  m_GIWorkflowMode: 0
+  m_EnableBakedLightmaps: 1
+  m_EnableRealtimeLightmaps: 1
+  m_RealtimeEnvironmentLighting: 1
+  m_BounceScale: 1
+  m_AlbedoBoost: 1
+  m_IndirectOutputScale: 1
+  m_UsingShadowmask: 1
+  m_BakeBackend: 1
+  m_LightmapMaxSize: 1024
+  m_BakeResolution: 40
+  m_Padding: 2
+  m_TextureCompression: 1
+  m_AO: 0
+  m_AOMaxDistance: 1
+  m_CompAOExponent: 1
+  m_CompAOExponentDirect: 0
+  m_ExtractAO: 0
+  m_MixedBakeMode: 2
+  m_LightmapsBakeMode: 1
+  m_FilterMode: 1
+  m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
+  m_ExportTrainingData: 0
+  m_TrainingDataDestination: TrainingData
+  m_RealtimeResolution: 2
+  m_ForceWhiteAlbedo: 0
+  m_ForceUpdates: 0
+  m_FinalGather: 0
+  m_FinalGatherRayCount: 256
+  m_FinalGatherFiltering: 1
+  m_PVRCulling: 1
+  m_PVRSampling: 1
+  m_PVRDirectSampleCount: 32
+  m_PVRSampleCount: 500
+  m_PVREnvironmentSampleCount: 500
+  m_PVREnvironmentReferencePointCount: 2048
+  m_LightProbeSampleCountMultiplier: 4
+  m_PVRBounces: 2
+  m_PVRMinBounces: 2
+  m_PVREnvironmentMIS: 0
+  m_PVRFilteringMode: 2
+  m_PVRDenoiserTypeDirect: 0
+  m_PVRDenoiserTypeIndirect: 0
+  m_PVRDenoiserTypeAO: 0
+  m_PVRFilterTypeDirect: 0
+  m_PVRFilterTypeIndirect: 0
+  m_PVRFilterTypeAO: 0
+  m_PVRFilteringGaussRadiusDirect: 1
+  m_PVRFilteringGaussRadiusIndirect: 5
+  m_PVRFilteringGaussRadiusAO: 2
+  m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+  m_PVRFilteringAtrousPositionSigmaIndirect: 2
+  m_PVRFilteringAtrousPositionSigmaAO: 1
+--- !u!1 &898263253
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 898263254}
+  - component: {fileID: 898263256}
+  - component: {fileID: 898263255}
+  m_Layer: 5
+  m_Name: RawImage
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &898263254
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 898263253}
+  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: []
+  m_Father: {fileID: 1180428450}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 1920, y: 1080}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &898263255
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 898263253}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 0
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Texture: {fileID: 0}
+  m_UVRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+--- !u!222 &898263256
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 898263253}
+  m_CullTransparentMesh: 0
+--- !u!1 &1180428446
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1180428450}
+  - component: {fileID: 1180428449}
+  - component: {fileID: 1180428448}
+  - component: {fileID: 1180428447}
+  m_Layer: 5
+  m_Name: Canvas
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &1180428447
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1180428446}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+--- !u!114 &1180428448
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1180428446}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, 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
+  m_PresetInfoIsWorld: 0
+--- !u!223 &1180428449
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1180428446}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 0
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  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 &1180428450
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1180428446}
+  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: 898263254}
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  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!1 &1553296572
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1553296575}
+  - component: {fileID: 1553296574}
+  - component: {fileID: 1553296573}
+  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 &1553296573
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1553296572}
+  m_Enabled: 1
+--- !u!20 &1553296574
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1553296572}
+  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_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  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 &1553296575
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1553296572}
+  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}
+--- !u!1 &2071340435
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2071340438}
+  - component: {fileID: 2071340437}
+  - component: {fileID: 2071340436}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &2071340436
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2071340435}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &2071340437
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2071340435}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &2071340438
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2071340435}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1001 &1962568788625176088
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 1280
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 720
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCFilters.Array.size
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 898263253}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCFilters.Array.data[0].Pid
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCFilters.Array.data[0].Vid
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 898263253}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_RootOrder
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: PreferH264
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCDrawers.Array.size
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderBeforeSceneRendering
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_Name
+      value: UVCDrawer
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: fa65cd0b0e2ffad4180eabf8fe755f9a, type: 3}

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2DScene.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: d9c653ce29884b648bd83d4066fe46c0
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 733 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2Dx2Scene.unity

@@ -0,0 +1,733 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 11
+  m_GIWorkflowMode: 0
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 1
+  m_LightmapEditorSettings:
+    serializedVersion: 10
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 500
+    m_PVRBounces: 2
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVRFilteringMode: 1
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ShowResolutionOverlay: 1
+  m_LightingDataAsset: {fileID: 0}
+  m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &544315098 stripped
+GameObject:
+  m_CorrespondingSourceObject: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+    type: 3}
+  m_PrefabInstance: {fileID: 1962568788625176088}
+  m_PrefabAsset: {fileID: 0}
+--- !u!114 &544315099
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 544315098}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: efb1bc18f15fa0546b998062ea4861a3, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  DefaultWidth: 1280
+  DefaultHeight: 720
+  UVCFilters:
+  - Description: C920R
+    Vid: 1133
+    Pid: 2093
+    DeviceName: 
+    IsExclude: 0
+  RenderTargets:
+  - {fileID: 1898103480}
+--- !u!1 &548459541
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 548459543}
+  - component: {fileID: 548459542}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &548459542
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 548459541}
+  m_Enabled: 1
+  serializedVersion: 8
+  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_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_Lightmapping: 4
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &548459543
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 548459541}
+  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 &898263253
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 898263254}
+  - component: {fileID: 898263256}
+  - component: {fileID: 898263255}
+  m_Layer: 5
+  m_Name: RawImageLeft
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &898263254
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 898263253}
+  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: []
+  m_Father: {fileID: 1180428450}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: -480, y: 0}
+  m_SizeDelta: {x: 840, y: 473}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &898263255
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 898263253}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: -98529514, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 0
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Texture: {fileID: 0}
+  m_UVRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+--- !u!222 &898263256
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 898263253}
+  m_CullTransparentMesh: 0
+--- !u!1 &1180428446
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1180428450}
+  - component: {fileID: 1180428449}
+  - component: {fileID: 1180428448}
+  - component: {fileID: 1180428447}
+  m_Layer: 5
+  m_Name: Canvas
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &1180428447
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1180428446}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 1301386320, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+--- !u!114 &1180428448
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1180428446}
+  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!223 &1180428449
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1180428446}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 0
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  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 &1180428450
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1180428446}
+  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: 898263254}
+  - {fileID: 1898103481}
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  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!1 &1553296572
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1553296575}
+  - component: {fileID: 1553296574}
+  - component: {fileID: 1553296573}
+  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 &1553296573
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1553296572}
+  m_Enabled: 1
+--- !u!20 &1553296574
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1553296572}
+  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 &1553296575
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1553296572}
+  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}
+--- !u!1 &1898103480
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1898103481}
+  - component: {fileID: 1898103483}
+  - component: {fileID: 1898103482}
+  m_Layer: 5
+  m_Name: RawImageRight
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &1898103481
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1898103480}
+  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: []
+  m_Father: {fileID: 1180428450}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 480, y: 0}
+  m_SizeDelta: {x: 840, y: 473}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &1898103482
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1898103480}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: -98529514, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 0
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_Texture: {fileID: 0}
+  m_UVRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+--- !u!222 &1898103483
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1898103480}
+  m_CullTransparentMesh: 0
+--- !u!1 &2071340435
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2071340438}
+  - component: {fileID: 2071340437}
+  - component: {fileID: 2071340436}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &2071340436
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2071340435}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &2071340437
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2071340435}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &2071340438
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2071340435}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1001 &1962568788625176088
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCFilters.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 898263253}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 898263253}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCFilters.Array.data[0].Vid
+      value: 1133
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCFilters.Array.data[0].Pid
+      value: 2140
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[1]
+      value: 
+      objectReference: {fileID: 1898103480}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCFilters.Array.data[0].Description
+      value: C922
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_RootOrder
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: UVCDrawers.Array.size
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultWidth
+      value: 1280
+      objectReference: {fileID: 0}
+    - target: {fileID: 7716261784260357304, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: DefaultHeight
+      value: 720
+      objectReference: {fileID: 0}
+    - target: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_Name
+      value: UVCDrawer
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: fa65cd0b0e2ffad4180eabf8fe755f9a, type: 3}

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC2Dx2Scene.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: c6f1bcfdae2398947a9a34689ff6c415
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 687 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC3DScene.unity

@@ -0,0 +1,687 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 170076734}
+  m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 11
+  m_GIWorkflowMode: 0
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 10
+    m_Resolution: 2
+    m_BakeResolution: 10
+    m_AtlasSize: 512
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 256
+    m_PVRBounces: 2
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVRFilteringMode: 1
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ShowResolutionOverlay: 1
+  m_LightingDataAsset: {fileID: 0}
+  m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &170076733
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 170076735}
+  - component: {fileID: 170076734}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &170076734
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 170076733}
+  m_Enabled: 1
+  serializedVersion: 8
+  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_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_Lightmapping: 1
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &170076735
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 170076733}
+  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 &534669902
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 534669905}
+  - component: {fileID: 534669904}
+  - component: {fileID: 534669903}
+  - component: {fileID: 534669906}
+  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 &534669903
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 534669902}
+  m_Enabled: 1
+--- !u!20 &534669904
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 534669902}
+  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 &534669905
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 534669902}
+  m_LocalRotation: {x: 0.13052616, y: 0, z: 0, w: 0.9914449}
+  m_LocalPosition: {x: 0, y: 2, z: -10}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 15, y: 0, z: 0}
+--- !u!114 &534669906
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 534669902}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: -768656878, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_EventMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_MaxRayIntersections: 0
+--- !u!1001 &585868312
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.size
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.size
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1922705223}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: CameraRenderSettings.Array.data[0].RenderTargets.Array.data[1]
+      value: 
+      objectReference: {fileID: 800007506}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[1]
+      value: 
+      objectReference: {fileID: 800007506}
+    - target: {fileID: 464229095961303548, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: RenderTargets.Array.data[0]
+      value: 
+      objectReference: {fileID: 1922705223}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_RootOrder
+      value: 4
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 6011951749156047501, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+        type: 3}
+      propertyPath: m_Name
+      value: UVCDrawer
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: fa65cd0b0e2ffad4180eabf8fe755f9a, type: 3}
+--- !u!1 &585868313 stripped
+GameObject:
+  m_CorrespondingSourceObject: {fileID: 7953172909807438327, guid: fa65cd0b0e2ffad4180eabf8fe755f9a,
+    type: 3}
+  m_PrefabInstance: {fileID: 585868312}
+  m_PrefabAsset: {fileID: 0}
+--- !u!114 &585868314
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 585868313}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: efb1bc18f15fa0546b998062ea4861a3, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  UVCFilters: []
+  RenderTargets:
+  - {fileID: 800007506}
+--- !u!1 &800007506
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 800007510}
+  - component: {fileID: 800007509}
+  - component: {fileID: 800007508}
+  - component: {fileID: 800007507}
+  m_Layer: 0
+  m_Name: Cylinder
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!136 &800007507
+CapsuleCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 800007506}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  m_Radius: 0.5000001
+  m_Height: 2
+  m_Direction: 1
+  m_Center: {x: 0.000000059604645, y: 0, z: -0.00000008940697}
+--- !u!23 &800007508
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 800007506}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  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: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 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 &800007509
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 800007506}
+  m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!4 &800007510
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 800007506}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: -6}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1397046144
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1397046147}
+  - component: {fileID: 1397046146}
+  - component: {fileID: 1397046145}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &1397046145
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1397046144}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &1397046146
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1397046144}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &1397046147
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1397046144}
+  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: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 5
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1922705223
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1922705228}
+  - component: {fileID: 1922705227}
+  - component: {fileID: 1922705226}
+  - component: {fileID: 1922705225}
+  - component: {fileID: 1922705231}
+  - component: {fileID: 1922705229}
+  m_Layer: 0
+  m_Name: Cube
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!65 &1922705225
+BoxCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1922705223}
+  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!23 &1922705226
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1922705223}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 280f2e40f1de1d940976f143e80c6030, 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: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 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 &1922705227
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1922705223}
+  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!4 &1922705228
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1922705223}
+  m_LocalRotation: {x: 0.32664078, y: 0.29516026, z: 0.13529904, w: 0.8876263}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 5, y: 5, z: 5}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 30, y: 45, z: 30}
+--- !u!114 &1922705229
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1922705223}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 38153cc94decf374e86c5eaef57facc7, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  TargetObject: {fileID: 0}
+--- !u!54 &1922705231
+Rigidbody:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1922705223}
+  serializedVersion: 2
+  m_Mass: 1
+  m_Drag: 0
+  m_AngularDrag: 0.05
+  m_UseGravity: 0
+  m_IsKinematic: 0
+  m_Interpolate: 0
+  m_Constraints: 0
+  m_CollisionDetection: 0

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scenes/UVC3DScene.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 534dbb7308777da4688d42c039024ab4
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scripts.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2fc9b626f18e84f488ed86b5a6ecf539
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 73 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scripts/CameraController.cs

@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+using Serenegiant;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using static Serenegiant.TouchEventManager;
+
+public class CameraController : MonoBehaviour
+{
+	/**
+	 * このスクリプトで操作するカメラ(GameObject)
+	 * 未割り当ての場合はこのスクリプトがセットされているGameObjectを使う
+	 */
+	public GameObject TargetCamera;
+
+	private TouchEventManager manager;
+	private Transform taregtTransform;
+	private Vector3 force = new Vector3();
+	private Vector2 touchPosition = new Vector2();
+
+	private const float FACTOR = 0.2f;
+	private const float DECAY_RATE = 0.95f;
+	private const float FORCE_LIMIT = 50;
+	private const float FORCE_LIMIT2 = FORCE_LIMIT * FORCE_LIMIT;
+	
+	// Start is called before the first frame update
+	void Start()
+    {
+		if (TargetCamera == null)
+		{   // TargetObjectが割り当てられていないときは
+			// このスクリプトがセットされているゲームオブジェクトを使う
+			TargetCamera = gameObject;
+		}
+		taregtTransform = TargetCamera.transform;
+		manager = new TouchEventManager();
+	}
+
+	// Update is called once per frame
+	void Update()
+    {
+		manager.Update();
+
+		var touch = manager.GetTouch();
+
+		switch (touch.state) {
+			case TouchState.Began:
+				touchPosition.Set(touch.position.x, touch.position.y);
+				break;
+			case TouchState.Moved:
+				var delta = touch.position - touchPosition;
+				// 移動量に応じて角度計算
+				float xAngle = delta.y * FACTOR;
+				float yAngle = -delta.x * FACTOR;
+
+				force.Set(xAngle, yAngle, 0.0f);
+				if (force.sqrMagnitude > FORCE_LIMIT2)
+				{
+					force = force.normalized * FORCE_LIMIT;
+				}
+				break;
+		}
+	}
+
+	void FixedUpdate()
+	{
+		// 回転させる
+		taregtTransform.Rotate(force * Time.deltaTime, Space.World);
+		// 減衰させる
+		force *= DECAY_RATE;
+	}
+
+}

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scripts/CameraController.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0c32ee072b65f5346ac9f54c8bf3f80c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 74 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scripts/CubeHandler.cs

@@ -0,0 +1,74 @@
+//#define ENABLE_LOG
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+
+using System;
+using UnityEngine;
+
+using UnityEngine.EventSystems;
+
+public class CubeHandler : MonoBehaviour,
+	IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
+{
+	/**
+	 * このスクリプトで操作するGameObject
+	 * 未割り当ての場合はこのスクリプトがセットされているGameObjectを使う
+	 */
+	public GameObject TargetObject;
+
+	private Transform taregtTransform;
+	private Vector3 force = new Vector3();
+
+	private const float FACTOR = 1.0f;
+	private const float DECAY_RATE = 0.90f;
+
+	// Start is called before the first frame update
+	void Start()
+	{	
+		if (TargetObject == null)
+		{   // TargetObjectが割り当てられていないときは
+			// このスクリプトがセットされているゲームオブジェクトを使う
+			TargetObject = gameObject;
+		}
+		taregtTransform = TargetObject.transform;
+	}
+
+//	// Update is called once per frame
+//	void Update()
+//	{
+//
+//	}
+
+	void FixedUpdate()
+	{
+		// 回転させる
+		taregtTransform.Rotate(force * Time.deltaTime, Space.World);
+		// 減衰させる
+		force *= DECAY_RATE;
+	}
+
+	public void OnBeginDrag(PointerEventData eventData)
+	{
+	}
+
+	public void OnDrag(PointerEventData eventData)
+	{
+		// 移動量に応じて角度計算
+		float xAngle = eventData.delta.y * FACTOR;
+		float yAngle = -eventData.delta.x * FACTOR;
+
+		force += new Vector3(xAngle, yAngle, 0.0f);
+	}
+
+	public void OnEndDrag(PointerEventData eventData)
+	{
+	}
+
+	public void OnPointerClick(PointerEventData eventData)
+	{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+		Console.WriteLine("OnClick:");
+#endif
+	}
+}

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scripts/CubeHandler.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 38153cc94decf374e86c5eaef57facc7
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 130 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scripts/TouchEventManager.cs

@@ -0,0 +1,130 @@
+//#define ENABLE_LOG
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+
+using UnityEngine;
+
+namespace Serenegiant {
+	public class TouchEventManager
+	{
+		public enum TouchState
+		{
+			// タッチ無し
+			None = -1,
+			// タッチ開始
+			Began = TouchPhase.Began,
+			// タッチ移動
+			Moved = TouchPhase.Moved,
+			// タッチ静止
+			Stationary = TouchPhase.Stationary,
+			// タッチ終了
+			Ended = TouchPhase.Ended,
+			// タッチキャンセル
+			Canceled = TouchPhase.Canceled,
+		}
+
+		public class TouchEvent
+		{
+			public Vector2 position;
+			public TouchState state;
+
+			/**
+			 * コンストラクタ
+			 * @param touched
+			 * @param position
+			 * @param phase
+			 */
+			public TouchEvent(Vector2? position = null, TouchState state = TouchState.Began)
+			{
+				if (position == null)
+				{
+					this.position = new Vector2(0, 0);
+				}
+				else
+				{
+					this.position = (Vector2)position;
+				}
+				this.state = state;
+			}
+
+			/**
+			 * コピーコンストラクタ
+			 * @param other
+			 */
+			public TouchEvent(TouchEvent other)
+			{
+				this.position = new Vector2(other.position.x, other.position.y);
+				this.state = other.state;
+			}
+		}
+
+		private TouchEvent touchEvent = new TouchEvent();
+
+		/**
+		 * デフォルトコンストラクタ
+		 */
+		public TouchEventManager()
+		{
+		}
+
+		/**
+		 * タッチ状態の更新
+		 * MonoBehaviourの下位クラスのUpdateから呼ぶこと
+		 */
+		public void Update()
+		{
+			touchEvent.state = TouchState.None;
+
+			if (Application.isEditor)
+			{   // エディタで実行中…マウスの状態でタッチイベントをシミュレートする
+				if (Input.GetMouseButtonDown(0))
+				{   // タッチしたとき
+					touchEvent.state = TouchState.Began;
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+				Console.WriteLine("タッチした:");
+#endif
+				}
+
+				if (Input.GetMouseButtonUp(0))
+				{   // 離したとき
+					touchEvent.state = TouchState.Ended;
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+				Console.WriteLine("タッチした:");
+#endif
+				}
+
+				if (Input.GetMouseButton(0))
+				{   // 押し続けているとき
+					touchEvent.state = TouchState.Moved;
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+				Console.WriteLine("押し続けている");
+#endif
+				}
+
+				if (touchEvent.state != TouchState.None)
+				{   // タッチイベントがあるときは座標を取得
+					touchEvent.position = Input.mousePosition;
+				}
+			}
+			else
+			{   // 実機で実行中
+				if (Input.touchCount > 0)
+				{
+					Touch touch = Input.GetTouch(0);
+					touchEvent.position = touch.position;
+					touchEvent.state = (TouchState)touch.phase;
+				}
+			}
+		}
+
+		/**
+		 * 現在のタッチ状態を取得
+		 */
+		public TouchEvent GetTouch()
+		{
+			return new TouchEvent(touchEvent);
+		}
+	}
+
+} // namespace Serenegiant

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Scripts/TouchEventManager.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b9ed63e9a3b1a784fb49814fc5234990
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Shaders.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 798b2cfb10abe8746a83344e1977c545
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 6 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Shaders/README.md

@@ -0,0 +1,6 @@
+Copyright (c) 2015 Nora
+Released under the MIT license
+http://opensource.org/licenses/mit-license.php
+
+Modified 2017 by Makoto Hamanaka <ham.lua@gmail.com>
+Modified 2019 by t_saki@serenegiant.com

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Shaders/README.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4ae395c32449fd94ea2911fc01b5b103
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 219 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Shaders/ThetaRealtimeEquirectangular1080p.shader

@@ -0,0 +1,219 @@
+// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
+
+// Copyright (c) 2015 Nora
+// Released under the MIT license
+// http://opensource.org/licenses/mit-license.php
+Shader "Theta/RealtimeEquirectangular1080p"
+{
+	Properties
+	{
+		[NoScaleOffset] _MainTex("Texture", 2D) = "white" {}
+		_UVOffset("UVOffset(Forward UV / Backward UV)", Vector) = (0.0, 0.0, 0.0, 0.0)
+
+		[KeywordEnum(Theta S 1080p, Theta S, Theta, Insta360 Air)] _Mode("Mode", Int) = 0
+	}
+
+	SubShader
+	{
+		Tags{ "RenderType" = "Overlay" "Queue" = "Overlay" "ForceNoShadowCasting" = "True" }
+//		Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" "ForceNoShadowCasting" = "True" }
+
+		ZTest Always
+		Cull Off
+		ZWrite Off
+
+		Pass
+		{
+			CGPROGRAM
+			#pragma vertex vert
+			#pragma fragment frag
+			#pragma multi_compile _MODE_THETA_S_1080P _MODE_THETA_S _MODE_THETA _MODE_INSTA360_AIR
+
+			#include "UnityCG.cginc"
+
+			struct appdata
+			{
+				float4 vertex : POSITION;
+				float2 uv : TEXCOORD0;
+			};
+
+			struct v2f
+			{
+				float2 uv : TEXCOORD0;
+				float4 vertex : SV_POSITION;
+			};
+
+			sampler2D _MainTex;
+			float4 _UVOffset;
+
+			#if defined(_MODE_THETA_S_1080P)
+				#define _RADIUS 0.4425
+				#define _TEXTURE_Y_OFFSET 0
+				#define _TEXTURE_Y_SCALE (640.0 / 720.0)
+				#define _FORWARD_ROTATION_DEGREE 0
+				#define _BACKWARD_ROTATION_DEGREE 0
+			#elif defined(_MODE_THETA_S)
+				#define _RADIUS 0.445
+				#define _TEXTURE_Y_OFFSET ((720.0 - 640.0) / 720.0)
+				#define _TEXTURE_Y_SCALE (640.0 / 720.0)
+				#define _FORWARD_ROTATION_DEGREE 0
+				#define _BACKWARD_ROTATION_DEGREE 0
+			#elif defined(_MODE_INSTA360_AIR)
+				#define _INSTA360_AIR_SENSOR_ROTATION_DEGREE  4.0
+				#define _RADIUS 0.47
+				#define _TEXTURE_Y_OFFSET 0
+				#define _TEXTURE_Y_SCALE 1
+				#define _FORWARD_ROTATION_DEGREE (-90 + _INSTA360_AIR_SENSOR_ROTATION_DEGREE)
+				#define _BACKWARD_ROTATION_DEGREE (90 + _INSTA360_AIR_SENSOR_ROTATION_DEGREE)
+			#else
+				#define _RADIUS 0.445
+				#define _TEXTURE_Y_OFFSET 0
+				#define _TEXTURE_Y_SCALE 1
+				#define _FORWARD_ROTATION_DEGREE 0
+				#define _BACKWARD_ROTATION_DEGREE 0
+			#endif
+
+			v2f vert (appdata v)
+			{
+				v2f o;
+				// MVP行列を掛ける
+				// mul(UNITY_MATRIX_MVP, v.vertex)と同じ処理だけどパフォーマンス良いらしい
+				o.vertex = UnityObjectToClipPos(v.vertex);
+				o.uv = v.uv;
+				// プラットフォームによる射影行列の違いを吸収
+				o.uv.y *= _ProjectionParams.x;
+				return o;
+			}
+
+			// 2次元変換行列 (3次元目は平行移動用に使う)
+			float3x3 rotate_matrix_radian(float rot) {
+				float sinX = sin(rot);
+				float cosX = cos(rot);
+				return float3x3(cosX, -sinX, 0, sinX, cosX, 0, 0, 0, 1);
+			}
+
+			// Scale/Rotate/Translate Matrix群
+			float3x3 rotate_matrix_degree(float rot) {
+				return rotate_matrix_radian(rot * UNITY_PI / 180.0);
+			}
+			float3x3 scale_matrix(float2 scale) {
+				return float3x3(scale.x, 0, 0, 0, scale.y, 0, 0, 0, 1);
+			}
+			float3x3 scaleX_matrix(float x) {
+				return float3x3(x, 0, 0, 0, 1, 0, 0, 0, 1);
+			}
+			float3x3 scaleY_matrix(float y) {
+				return float3x3(1, 0, 0, 0, y, 0, 0, 0, 1);
+			}
+			float3x3 translate_matrix(float2 vec) {
+				return float3x3(1, 0, 0, 0, 1, 0, vec.x, vec.y, 1);
+			}
+			float3x3 translateX_matrix(float x) {
+				return float3x3(1, 0, 0, 0, 1, 0, x, 0, 1);
+			}
+			float3x3 translateY_matrix(float y) {
+				return float3x3(1, 0, 0, 0, 1, 0, 0, y, 1);
+			}
+
+			float3x3 texture_matrix3() {
+				float3x3 mat = float3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
+				mat = mul(mat, scaleY_matrix(_TEXTURE_Y_SCALE));
+				mat = mul(mat, translateY_matrix(_TEXTURE_Y_OFFSET));
+				return mat;
+			}
+
+			// forward用変換行列
+			// (0,0)を中心として半径1の範囲の座標、をテクスチャ座標に変換するmatrix
+			// 計算量多いようだが、すべてコンパイル時に解決されるはず。
+			float3x3 forward_matrix3() {
+				float3x3 mat = float3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
+				mat = mul(mat, rotate_matrix_degree(_FORWARD_ROTATION_DEGREE));
+				mat = mul(mat, translate_matrix(float2(0.5, 0.5)));
+				// 裏側なので逆方向にする
+				mat = mul(mat, scaleX_matrix(-1));
+				mat = mul(mat, translateX_matrix(1));
+				// XのUV幅は半分なので x0.5
+				mat = mul(mat, scaleX_matrix(0.5));
+				// オフセット
+				mat = mul(mat, translate_matrix(_UVOffset.yx));
+				mat = mul(mat, texture_matrix3());
+				return mat;
+			}
+
+			// backward用変換行列
+			// (0,0)を中心として半径1の範囲の座標、をテクスチャ座標に変換するmatrix
+			// 計算量多いようだが、すべてコンパイル時に解決されるはず。
+			float3x3 backward_matrix3() {
+				float3x3 mat = float3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
+				mat = mul(mat, rotate_matrix_degree(_BACKWARD_ROTATION_DEGREE));
+				mat = mul(mat, translate_matrix(float2(0.5, 0.5)));
+				// 片目分のUV幅は半分なので x0.5
+				mat = mul(mat, scaleX_matrix(0.5));
+				// 右側なので +0.5
+				mat = mul(mat, translateX_matrix(0.5));
+				// Y逆方向
+				mat = mul(mat, scaleY_matrix(-1));
+				mat = mul(mat, translateY_matrix(1));
+				// オフセット
+				mat = mul(mat, translate_matrix(_UVOffset.wz));
+				mat = mul(mat, texture_matrix3());
+				return mat;
+			}
+
+			float2 convert_for_forward(float2 st) {
+				return mul(float3(st.x, st.y, 1), forward_matrix3()).xy;
+			}
+
+			float2 convert_for_backward(float2 st) {
+				return mul(float3(st.x, st.y, 1), backward_matrix3()).xy;
+			}
+
+			float4 frag(v2f i) : SV_Target
+			{
+//				float2 revUV = i.uv;
+				float2 revUV = float2(i.uv.x, 1.0 - i.uv.y);	// THETAの画像そのままだと上下が入れ替わってしまうので対策
+				if (i.uv.x <= 0.5) {
+					revUV.x = 1.0 - revUV.x * 2.0;
+				}
+				else {
+					revUV.x = 1.0 - (revUV.x - 0.5) * 2.0;
+				}
+
+				revUV *= UNITY_PI;
+
+				float3 p = float3(cos(revUV.x), cos(revUV.y), sin(revUV.x));
+				p.xz *= sqrt(1.0 - p.y * p.y);
+
+				float r = 1.0 - asin(p.z) / (UNITY_PI / 2.0);
+				float2 st = float2(p.y, p.x);
+
+				st *= r / sqrt(1.0 - p.z * p.z);
+				st *= _RADIUS;
+
+				// stは (0,0)を中心としたFisheye座標
+				float4 col;
+				if (i.uv.x <= 0.5)
+				{	// 後
+					st = convert_for_backward(st);
+					#if !defined(SHADER_API_OPENGL)
+					col = tex2Dlod(_MainTex, float4(st, 0.0, 0.0));
+					#else // Memo: OpenGL not supported tex2Dlod.( Texture should be setting to generateMipMap = off. )
+					col = tex2D(_MainTex, st);
+					#endif
+				}
+				else {
+					// 前
+					st = convert_for_forward(st);
+					#if !defined(SHADER_API_OPENGL)
+					col = tex2Dlod(_MainTex, float4(st, 0.0, 0.0));
+					#else // Memo: OpenGL not supported tex2Dlod.( Texture should be setting to generateMipMap = off. )
+					col = tex2D(_MainTex, st);
+					#endif
+				}
+
+				return col;
+			}
+			ENDCG
+		}
+	}
+}

+ 9 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Shaders/ThetaRealtimeEquirectangular1080p.shader.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 91b8677abe2e60d48a8941053cf517ff
+ShaderImporter:
+  externalObjects: {}
+  defaultTextures: []
+  nonModifiableTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Spheres.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6449a2c9e370a1241a26bf18c8de4417
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 3 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Spheres/README.md

@@ -0,0 +1,3 @@
+こちらのフォルダ内のファイルは伊藤周氏 (twitter @warapuri)の公開された細かいポリゴンの天球モデルです。
+This file in this folder is precise celestial sphere model published by Shu Ito (twitter @warapuri).
+https://twitter.com/warapuri/status/480915916645863424

+ 7 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Spheres/README.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 607cccaa57d583f43be0990c456074ed
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/UVC4UnityAndroidPlugin/Samples/Spheres/Sphere100.fbx


+ 97 - 0
Assets/UVC4UnityAndroidPlugin/Samples/Spheres/Sphere100.fbx.meta

@@ -0,0 +1,97 @@
+fileFormatVersion: 2
+guid: 368d458452cb14c439840c35167fa7b4
+ModelImporter:
+  serializedVersion: 23
+  fileIDToRecycleName:
+    100000: //RootNode
+    400000: //RootNode
+    2100000: phong1
+    2300000: //RootNode
+    3300000: //RootNode
+    4300000: pSphere1
+  externalObjects: {}
+  materials:
+    importMaterials: 1
+    materialName: 0
+    materialSearch: 1
+    materialLocation: 1
+  animations:
+    legacyGenerateAnimations: 4
+    bakeSimulation: 0
+    resampleCurves: 1
+    optimizeGameObjects: 0
+    motionNodeName: 
+    rigImportErrors: 
+    rigImportWarnings: 
+    animationImportErrors: 
+    animationImportWarnings: 
+    animationRetargetingWarnings: 
+    animationDoRetargetingWarnings: 0
+    importAnimatedCustomProperties: 0
+    importConstraints: 0
+    animationCompression: 1
+    animationRotationError: 0.5
+    animationPositionError: 0.5
+    animationScaleError: 0.5
+    animationWrapMode: 0
+    extraExposedTransformPaths: []
+    extraUserProperties: []
+    clipAnimations: []
+    isReadable: 1
+  meshes:
+    lODScreenPercentages: []
+    globalScale: 1
+    meshCompression: 0
+    addColliders: 0
+    useSRGBMaterialColor: 1
+    importVisibility: 1
+    importBlendShapes: 1
+    importCameras: 1
+    importLights: 1
+    swapUVChannels: 0
+    generateSecondaryUV: 0
+    useFileUnits: 1
+    optimizeMeshForGPU: 1
+    keepQuads: 0
+    weldVertices: 1
+    preserveHierarchy: 0
+    indexFormat: 0
+    secondaryUVAngleDistortion: 8
+    secondaryUVAreaDistortion: 15.000001
+    secondaryUVHardAngle: 88
+    secondaryUVPackMargin: 4
+    useFileScale: 1
+    previousCalculatedGlobalScale: 1
+    hasPreviousCalculatedGlobalScale: 0
+  tangentSpace:
+    normalSmoothAngle: 60
+    normalImportMode: 0
+    tangentImportMode: 3
+    normalCalculationMode: 4
+    legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+    blendShapeNormalImportMode: 1
+    normalSmoothingSource: 0
+  importAnimation: 1
+  copyAvatar: 0
+  humanDescription:
+    serializedVersion: 2
+    human: []
+    skeleton: []
+    armTwist: 0.5
+    foreArmTwist: 0.5
+    upperLegTwist: 0.5
+    legTwist: 0.5
+    armStretch: 0.05
+    legStretch: 0.05
+    feetSpacing: 0
+    rootMotionBoneName: 
+    hasTranslationDoF: 0
+    hasExtraRoot: 0
+    skeletonHasParents: 1
+  lastHumanDescriptionAvatarSource: {instanceID: 0}
+  animationType: 0
+  humanoidOversampling: 1
+  additionalBone: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/UVC4UnityAndroidPlugin/Scripts.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 849559115caa7dd4babed02fbf123988
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 334 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/AndroidUtils.cs

@@ -0,0 +1,334 @@
+//#define ENABLE_LOG
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using UnityEngine;
+
+#if UNITY_ANDROID
+#if UNITY_2018_3_OR_NEWER
+using UnityEngine.Android;
+#endif
+#endif
+
+namespace Serenegiant
+{
+
+	public class AndroidUtils : MonoBehaviour
+	{
+		public const string FQCN_UNITY_PLAYER = "com.unity3d.player.UnityPlayer";
+		public const string PERMISSION_CAMERA = "android.permission.CAMERA";
+
+		public enum PermissionGrantResult
+		{
+			PERMISSION_GRANT = 0,
+			PERMISSION_DENY = -1,
+			PERMISSION_DENY_AND_NEVER_ASK_AGAIN = -2
+		}
+
+		private const string TAG = "AndroidUtils#";
+		private const string FQCN_PLUGIN = "com.serenegiant.androidutils.AndroidUtils";
+
+		//--------------------------------------------------------------------------------
+		/**
+		 * ライフサイクルイベント用のデリゲーター
+		 * @param resumed true: onResume, false: onPause
+		 */
+		public delegate void LifecycleEventHandler(bool resumed);
+
+		/***
+		 * GrantPermissionでパーミッションを要求したときのコールバック用delegateer
+		 * @param permission
+		 * @param grantResult 0:grant, -1:deny, -2:denyAndNeverAskAgain
+		*/
+		public delegate void OnPermission(string permission, PermissionGrantResult result);
+
+		//--------------------------------------------------------------------------------
+		/**
+		 * パーミッション要求時のタイムアウト
+		 */
+		public static float PermissionTimeoutSecs = 30;
+	
+		public event LifecycleEventHandler LifecycleEvent;
+
+		public static bool isPermissionRequesting;
+		private static PermissionGrantResult grantResult;
+
+		void Awake()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}Awake:");
+#endif
+#if UNITY_ANDROID
+			Input.backButtonLeavesApp = true;   // 端末のバックキーでアプリを終了できるようにする
+			Initialize();
+#endif
+		}
+
+		//--------------------------------------------------------------------------------
+		// Java側からのイベントコールバック
+
+		/**
+		 * onStartイベント
+		 */
+		public void OnStartEvent()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}OnStartEvent:");
+#endif
+		}
+
+		/**
+		 * onResumeイベント
+		 */
+		public void OnResumeEvent()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}OnResumeEvent:");
+#endif
+			LifecycleEvent?.Invoke(true);
+		}
+
+		/**
+		 * onPauseイベント
+		 */
+		public void OnPauseEvent()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}OnPauseEvent:");
+#endif
+			LifecycleEvent?.Invoke(false);
+		}
+
+		/**
+		 * onStopイベント
+		 */
+		public void OnStopEvent()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}OnStopEvent:");
+#endif
+		}
+
+		/**
+		 * パーミッションを取得できた
+		 */
+		public void OnPermissionGrant()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}OnPermissionGrant:");
+#endif
+			grantResult = PermissionGrantResult.PERMISSION_GRANT;
+			isPermissionRequesting = false;
+		}
+
+		/**
+		 * パーミッションを取得できなかった
+		 */
+		public void OnPermissionDeny()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}OnPermissionDeny:");
+#endif
+			grantResult = PermissionGrantResult.PERMISSION_DENY;
+			isPermissionRequesting = false;
+		}
+
+		/**
+		 * パーミッションを取得できずパーミッションダイアログを再び表示しないように設定された
+		 */
+		public void OnPermissionDenyAndNeverAskAgain()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}OnPermissionDenyAndNeverAskAgain:");
+#endif
+			grantResult = PermissionGrantResult.PERMISSION_DENY_AND_NEVER_ASK_AGAIN;
+			isPermissionRequesting = false;
+		}
+
+		//--------------------------------------------------------------------------------
+#if UNITY_ANDROID
+		/**
+		 * プラグインの初期化実行
+		 */
+		private void Initialize()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}Initialize:{gameObject.name}");
+#endif
+			using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_PLUGIN))
+			{
+				clazz.CallStatic("initialize",
+					AndroidUtils.GetCurrentActivity(), gameObject.name);
+			}
+		}
+
+		/**
+		 * 指定したパーミッションを保持しているかどうかを取得
+		 * @param permission
+		 * @param 指定したパーミッションを保持している
+		 */
+		public static bool HasPermission(string permission)
+		{
+			using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_PLUGIN))
+			{
+				return clazz.CallStatic<bool>("hasPermission",
+					AndroidUtils.GetCurrentActivity(), permission);
+			}
+		}
+
+		/**
+		 * 指定したパーミッションの説明を表示する必要があるかどうかを取得
+		 * @param permission
+		 * @param 指定したパーミッションの説明を表示する必要がある
+		 */
+		public static bool ShouldShowRequestPermissionRationale(string permission)
+		{
+			using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_PLUGIN))
+			{
+				return clazz.CallStatic<bool>("shouldShowRequestPermissionRationale",
+					AndroidUtils.GetCurrentActivity(), permission);
+			}
+		}
+
+		/**
+		 * パーミッション要求
+		 * こっちはJava側でRationaleの処理等を行わない
+		 * @param permission
+		 * @param callback
+		 */
+		public static IEnumerator RequestPermission(string permission, OnPermission callback)
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}GrantPermission:{permission}");
+#endif
+			if (!HasPermission(permission))
+			{
+				grantResult = PermissionGrantResult.PERMISSION_DENY;
+				isPermissionRequesting = true;
+				using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_PLUGIN))
+				{
+					clazz.CallStatic("requestPermission",
+						AndroidUtils.GetCurrentActivity(), permission);
+				}
+				float timeElapsed = 0;
+				while (isPermissionRequesting)
+				{
+					if ((PermissionTimeoutSecs > 0) && (timeElapsed > PermissionTimeoutSecs))
+					{
+						isPermissionRequesting = false;
+						yield break;
+					}
+					timeElapsed += Time.deltaTime;
+					yield return null;
+				}
+				callback(permission, grantResult);
+			}
+			else
+			{
+				callback(permission, PermissionGrantResult.PERMISSION_GRANT);
+			}
+	
+			yield break;
+		}
+
+		/**
+		 * パーミッション要求
+		 * こっちはJava側でRationaleの処理等を行う
+		 * @param permission
+		 * @param callback
+		 */
+		public static IEnumerator GrantPermission(string permission, OnPermission callback)
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}GrantPermission:{permission}");
+#endif
+			if (!HasPermission(permission))
+			{
+				grantResult = PermissionGrantResult.PERMISSION_DENY;
+				isPermissionRequesting = true;
+				using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_PLUGIN))
+				{
+					clazz.CallStatic("grantPermission",
+						AndroidUtils.GetCurrentActivity(), permission);
+				}
+				float timeElapsed = 0;
+				while (isPermissionRequesting)
+				{
+					if ((PermissionTimeoutSecs > 0) && (timeElapsed > PermissionTimeoutSecs))
+					{
+						isPermissionRequesting = false;
+						yield break;
+					}
+					timeElapsed += Time.deltaTime;
+						yield return null;
+				}
+				callback(permission, grantResult);
+			}
+			else
+			{
+				callback(permission, PermissionGrantResult.PERMISSION_GRANT);
+			}
+	
+			yield break;
+		}
+
+		/**
+		 * カメラパーミッションを要求
+		 * @param callback
+		 */
+		public static IEnumerator GrantCameraPermission(OnPermission callback)
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}GrantCameraPermission:");
+#endif
+			if (CheckAndroidVersion(23))
+			{
+				// Android9以降ではUVC機器アクセスにもCAMERAパーミッションが必要
+				yield return GrantPermission(PERMISSION_CAMERA, callback);
+			}
+			else
+			{
+				// Android 6 未満ではパーミッション要求処理は不要
+				callback(PERMISSION_CAMERA, PermissionGrantResult.PERMISSION_GRANT);
+			}
+
+			yield break;
+		}
+
+
+		//================================================================================
+
+		/**
+		 * UnityPlayerActivityを取得
+		 */
+		public static AndroidJavaObject GetCurrentActivity()
+		{
+			using (AndroidJavaClass playerClass = new AndroidJavaClass(FQCN_UNITY_PLAYER))
+			{
+				return playerClass.GetStatic<AndroidJavaObject>("currentActivity");
+			}
+		}
+
+		/**
+		 * 指定したバージョン以降かどうかを確認
+		 * @param apiLevel
+		 * @return true: 指定したバージョン以降で実行されている, false: 指定したバージョンよりも古い端末で実行されている
+		 */
+		public static bool CheckAndroidVersion(int apiLevel)
+		{
+			using (var VERSION = new AndroidJavaClass("android.os.Build$VERSION"))
+			{
+				return VERSION.GetStatic<int>("SDK_INT") >= apiLevel;
+			}
+		}
+
+	} // class AndroidUtils
+
+} // namespace Serenegiant
+
+#endif // #if UNITY_ANDROID

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/AndroidUtils.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6eca0239a3e830b45b761684e2a8c8ca
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 17 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/ComponentRestrictionAttribute.cs

@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+using System;
+using UnityEngine;
+
+[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
+public class ComponentRestrictionAttribute : PropertyAttribute
+{
+	public readonly Type type;
+	public ComponentRestrictionAttribute(Type type)
+	{
+		this.type = type;
+	}
+
+} // class ComponentRestrictionAttribute
+

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/ComponentRestrictionAttribute.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6fda646575989d340a5c638a74eba42e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 58 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/Debug.cs

@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+#if NDEBUG
+
+/*
+ * Debug.Log等によるコンソールへの出力を抑制する場合には
+ * Player SettingsのScripting Define SymbolsにNDEBUGを
+ * 追加するとコンソール出力を無効化できる。
+ * ただしUnityEngine.Debug.Logのようにフルパス指定している場合には
+ * 無効化できない。
+ */
+using UnityEngine;
+using System.Diagnostics;
+
+public static class Debug
+{
+	[Conditional("DUMMY")] public static void Assert(bool condition, string message, Object context) {}
+	[Conditional("DUMMY")] public static void Assert(bool condition, object message, Object context) {}
+	[Conditional("DUMMY")] public static void Assert(bool condition, string message) {}
+	[Conditional("DUMMY")] public static void Assert(bool condition, object message) {}
+	[Conditional("DUMMY")] public static void Assert(bool condition, Object context) {}
+	[Conditional("DUMMY")] public static void Assert(bool condition) {}
+	[Conditional("DUMMY")] public static void Assert(bool condition, string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void AssertFormat(bool condition, string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void AssertFormat(bool condition, Object context, string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void Break() {}
+	[Conditional("DUMMY")] public static void ClearDeveloperConsole() {}
+	[Conditional("DUMMY")] public static void DebugBreak() {}
+	[Conditional("DUMMY")] public static void DrawLine(Vector3 start, Vector3 end, Color color, float duration, bool depthTest) {}
+	[Conditional("DUMMY")] public static void DrawLine(Vector3 start, Vector3 end, Color color, float duration) {}
+	[Conditional("DUMMY")] public static void DrawLine(Vector3 start, Vector3 end) {}
+	[Conditional("DUMMY")] public static void DrawLine(Vector3 start, Vector3 end, Color color) {}
+	[Conditional("DUMMY")] public static void DrawRay(Vector3 start, Vector3 dir, Color color, float duration) {}
+	[Conditional("DUMMY")] public static void DrawRay(Vector3 start, Vector3 dir, Color color, float duration, bool depthTest) {}
+	[Conditional("DUMMY")] public static void DrawRay(Vector3 start, Vector3 dir) {}
+	[Conditional("DUMMY")] public static void DrawRay(Vector3 start, Vector3 dir, Color color) {}
+	[Conditional("DUMMY")] public static void Log(object message) {}
+	[Conditional("DUMMY")] public static void Log(object message, Object context) {}
+	[Conditional("DUMMY")] public static void LogAssertion(object message, Object context) {}
+	[Conditional("DUMMY")] public static void LogAssertion(object message) {}
+	[Conditional("DUMMY")] public static void LogAssertionFormat(Object context, string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void LogAssertionFormat(string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void LogError(object message, Object context) {}
+	[Conditional("DUMMY")] public static void LogError(object message) {}
+	[Conditional("DUMMY")] public static void LogErrorFormat(string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void LogErrorFormat(Object context, string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void LogException(System.Exception exception, Object context) {}
+	[Conditional("DUMMY")] public static void LogException(System.Exception exception) {}
+	[Conditional("DUMMY")] public static void LogFormat(Object context, string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void LogFormat(string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void LogWarning(object message) {}
+	[Conditional("DUMMY")] public static void LogWarning(object message, Object context) {}
+	[Conditional("DUMMY")] public static void LogWarningFormat(string format, params object[] args) {}
+	[Conditional("DUMMY")] public static void LogWarningFormat(Object context, string format, params object[] args) {}
+}
+
+#endif

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/Debug.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 06f19ee3566be4244a3c63ed0e351cf1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 51 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/IUVCDrawer.cs

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Serenegiant.UVC
+{
+
+	/**
+	 * UVC関係のイベントハンドリングインターフェース
+	 */
+	public interface IUVCDrawer
+	{
+		/**
+		 * UVC機器が接続された
+		 * @param manager 呼び出し元のUVCManager
+		 * @param device 接続されたUVC機器情報
+		 * @return true: UVC機器を使う, false: UVC機器を使わない
+		 */
+		bool OnUVCAttachEvent(UVCManager manager, UVCDevice device);
+		/**
+		 * UVC機器が取り外された
+		 * @param manager 呼び出し元のUVCManager
+		 * @param device 接続されたUVC機器情報
+		 */
+		void OnUVCDetachEvent(UVCManager manager, UVCDevice device);
+		/**
+		 * IUVCDrawerが指定したUVC機器の映像を描画できるかどうかを取得
+		 * @param manager 呼び出し元のUVCManager
+		 * @param device 接続されたUVC機器情報
+		 */
+		bool CanDraw(UVCManager manager, UVCDevice device);
+		/**
+		 * UVC機器からの映像取得を開始した
+		 * @param manager 呼び出し元のUVCManager
+		 * @param device 接続されたUVC機器情報
+		 * @param tex UVC機器からの映像を受け取るTextureオブジェクト
+		 */
+		void OnUVCStartEvent(UVCManager manager, UVCDevice device, Texture tex);
+		/**
+		 * UVC機器からの映像取得を終了した
+		 * @param manager 呼び出し元のUVCManager
+		 * @param device 接続されたUVC機器情報
+		 */
+		void OnUVCStopEvent(UVCManager manager, UVCDevice device);
+
+	}   // interface IUVCDrawer
+
+}	// namespace Serenegiant.UVC

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/IUVCDrawer.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3179be036ced68847bdd1e804eeb989c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 139 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/UVCDevice.cs

@@ -0,0 +1,139 @@
+//#define ENABLE_LOG
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+
+using System;
+using System.Runtime.InteropServices;
+
+/*
+ * THETA S  vid:1482, pid:1001
+ * THETA V  vid:1482, pid:1002
+ * THETA Z1 vid:1482, pid:1005
+ */
+
+namespace Serenegiant.UVC
+{
+
+	[Serializable]
+	public class UVCDevice
+	{
+		public readonly Int32 id;
+		public readonly int vid;
+		public readonly int pid;
+		public readonly int deviceClass;
+		public readonly int deviceSubClass;
+		public readonly int deviceProtocol;
+
+		public readonly string name;
+
+		public UVCDevice(IntPtr devicePtr) {
+			id = GetId(devicePtr);
+			vid = GetVendorId(devicePtr);
+			pid = GetProductId(devicePtr);
+			name = GetName(devicePtr);
+			deviceClass = GetDeviceClass(devicePtr);
+			deviceSubClass = GetDeviceSubClass(devicePtr);
+			deviceProtocol = GetDeviceProtocol(devicePtr);
+		}
+
+		public override string ToString()
+		{
+			return $"{base.ToString()}(id={id},vid={vid},pid={pid},name={name},deviceClass={deviceClass},deviceSubClass={deviceSubClass},deviceProtocol={deviceProtocol})";
+		}
+
+
+		/**
+		 * Ricohの製品かどうか
+		 * @param info
+		 */
+		public bool IsRicoh
+		{
+			get { return (vid == 1482); }
+		}
+
+        /**
+		 * THETA S/V/Z1のいずれかかどうか
+		 */
+        public bool IsTHETA
+        {
+            get { return IsTHETA_S || IsTHETA_V || IsTHETA_Z1; }
+        }
+   
+		/**
+		 * THETA Sかどうか
+		 */
+		public bool IsTHETA_S
+		{
+			get { return (vid == 1482) && (pid == 10001); }
+		}
+
+		/**
+		 * THETA Vかどうか
+		 */
+		public bool IsTHETA_V
+		{
+			// THETA Vからのpid=872はUVCでなくて動かないので注意(THETA側は静止画/動画モード)
+			get { return (vid == 1482) && (pid == 10002); }
+		}
+
+        /**
+		 * THETA Z1かどうか
+		 * @param info
+		 */
+        public bool IsTHETA_Z1
+        {
+            // THETA Z1からのpid=877はUVCではなくて動かないので注意(THETA側は静止画/動画モード)
+            get { return (vid == 1482) && (pid == 10005); }
+        }
+
+        //--------------------------------------------------------------------------------
+        // プラグインのインターフェース関数
+        //--------------------------------------------------------------------------------
+        /**
+		 * 機器idを取得(これだけはpublicにする)
+		 */
+        [DllImport("unityuvcplugin", EntryPoint = "DeviceInfo_get_id")]
+		public static extern Int32 GetId(IntPtr devicePtr);
+
+		/**
+			* デバイスクラスを取得
+			*/
+		[DllImport("unityuvcplugin", EntryPoint = "DeviceInfo_get_device_class")]
+		private static extern Byte GetDeviceClass(IntPtr devicePtr);
+
+		/**
+			* デバイスサブクラスを取得
+			*/
+		[DllImport("unityuvcplugin", EntryPoint = "DeviceInfo_get_device_sub_class")]
+		private static extern Byte GetDeviceSubClass(IntPtr devicePtr);
+
+		/**
+			* デバイスプロトコルを取得
+			*/
+		[DllImport("unityuvcplugin", EntryPoint = "DeviceInfo_get_device_protocol")]
+		private static extern Byte GetDeviceProtocol(IntPtr devicePtr);
+
+		/**
+			* ベンダーIDを取得
+			*/
+		[DllImport("unityuvcplugin", EntryPoint = "DeviceInfo_get_vendor_id")]
+		private static extern UInt16 GetVendorId(IntPtr devicePtr);
+
+		/**
+			* プロダクトIDを取得
+			*/
+		[DllImport("unityuvcplugin", EntryPoint = "DeviceInfo_get_product_id")]
+		private static extern UInt16 GetProductId(IntPtr devicePtr);
+
+		/**
+			* 機器名を取得
+			*/
+		[DllImport("unityuvcplugin", EntryPoint = "DeviceInfo_get_name")]
+		[return: MarshalAs(UnmanagedType.LPStr)]
+		private static extern string GetName(IntPtr devicePtr);
+
+	} // UVCDevice
+
+} // namespace Serenegiant.UVC
+

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/UVCDevice.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b25de6a40539b4e4f8010de7e4264822
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 387 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/UVCDrawer.cs

@@ -0,0 +1,387 @@
+#define ENABLE_LOG
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace Serenegiant.UVC
+{
+
+    public class UVCDrawer : MonoBehaviour, IUVCDrawer
+    {
+        /**
+		 * IUVCSelectorがセットされていないとき
+		 * またはIUVCSelectorが解像度選択時にnullを
+		 * 返したときのデフォルトの解像度(幅)
+		 */
+        public int DefaultWidth = 1280;
+        /**
+		 * IUVCSelectorがセットされていないとき
+		 * またはIUVCSelectorが解像度選択時にnullを
+		 * 返したときのデフォルトの解像度(高さ)
+		 */
+        public int DefaultHeight = 720;
+
+
+        /**
+		 * 接続時及び描画時のフィルタ用
+		 */
+        public UVCFilter[] UVCFilters;
+
+        /**
+		 * GameObject保留UVC设备的视频目标材质
+         * 如果未设置,则使用与分配此脚本相同的GameObjec。
+		 */
+        public List<GameObject> RenderTargets;
+
+        [HideInInspector]
+        public Action<Texture> StartPreviewAction;
+        [HideInInspector]
+        public Action StopPreviewAction;
+        //--------------------------------------------------------------------------------
+        private const string TAG = "UVCDrawer#";
+
+        /**
+		 * UVC機器からの映像の描画先Material
+		 * TargetGameObjectから取得する
+		 * 優先順位:
+		 *	 TargetGameObjectのSkybox
+		 *	 > TargetGameObjectのRenderer
+		 *	 > TargetGameObjectのRawImage
+		 *	 > TargetGameObjectのMaterial
+		 * いずれの方法でも取得できなければStartでUnityExceptionを投げる
+		 */
+        private UnityEngine.Object[] TargetMaterials;
+        /**
+		 * オリジナルのテクスチャ
+		 * UVCカメラ映像受け取り用テクスチャをセットする前に
+		 * GetComponent<Renderer>().material.mainTextureに設定されていた値
+		 */
+        private Texture[] SavedTextures;
+
+        private Quaternion[] quaternions;
+
+
+        //================================================================================
+
+        // Start is called before the first frame update
+        void Start()
+        {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}Start:");
+#endif
+            UpdateTarget();
+
+        }
+
+        //		// Update is called once per frame
+        //		void Update()
+        //		{
+        //
+        //		}
+
+        //================================================================================
+
+        /**
+		 * UVC機器が接続された
+		 * IOnUVCAttachHandlerの実装
+		 * @param manager 呼び出し元のUVCManager
+		 * @param device 対象となるUVC機器の情報
+		 * @return true: UVC機器を使用する, false: UVC機器を使用しない
+		 */
+        public bool OnUVCAttachEvent(UVCManager manager, UVCDevice device)
+        {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}OnUVCAttachEvent:{device}");
+#endif
+            // XXX 今の実装では基本的に全てのUVC機器を受け入れる
+            // ただしTHETA SとTHETA VとTHETA Z1は映像を取得できないインターフェースがあるのでオミットする
+            // CanDrawと同様にUVC機器フィルターをインスペクタで設定できるようにする
+            var result = !device.IsRicoh || device.IsTHETA;
+
+            result &= UVCFilter.Match(device, UVCFilters);
+
+            return result;
+        }
+
+        /**
+		 * UVC機器が取り外された
+		 * IOnUVCDetachEventHandlerの実装
+		 * @param manager 呼び出し元のUVCManager
+		 * @param device 対象となるUVC機器の情報
+		 */
+        public void OnUVCDetachEvent(UVCManager manager, UVCDevice device)
+        {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}OnUVCDetachEvent:{device}");
+#endif
+        }
+
+        //		/**
+        //		 * 解像度選択
+        //		 * IOnUVCSelectSizeHandlerの実装
+        //		 * @param manager 呼び出し元のUVCManager
+        //		 * @param device 対象となるUVC機器の情報
+        //		 * @param formats 対応している解像度についての情報
+        //		 */
+        //		public SupportedFormats.Size OnUVCSelectSize(UVCManager manager, UVCDevice device, SupportedFormats formats)
+        //		{
+        //#if (!NDEBUG && DEBUG && ENABLE_LOG)
+        //			Console.WriteLine($"{TAG}OnUVCSelectSize:{device}");
+        //#endif
+        //			if (device.IsTHETA_V || device.IsTHETA_Z1)
+        //			{
+        //#if (!NDEBUG && DEBUG && ENABLE_LOG)
+        //				Console.WriteLine($"{TAG}OnUVCSelectSize:THETA V/Z1");
+        //#endif
+        //				return FindSize(formats, 3840, 1920);
+        //			}
+        //			else if (device.IsTHETA_S)
+        //			{
+        //#if (!NDEBUG && DEBUG && ENABLE_LOG)
+        //				Console.WriteLine($"{TAG}OnUVCSelectSize:THETA S");
+        //#endif
+        //				return FindSize(formats, 1920, 1080);
+        //			}
+        //			else
+        //			{
+        //#if (!NDEBUG && DEBUG && ENABLE_LOG)
+        //				Console.WriteLine($"{TAG}OnUVCSelectSize:other UVC device,{device}");
+        //#endif
+        //				return formats.Find(DefaultWidth, DefaultHeight);
+        //			}
+        //		}
+
+        /**
+		 * 获取IUVCdrawer是否可以绘制指定的UVC设备的视频
+		 * 实现IUVCdrawer
+		 * @param manager 调用方UVCmanager
+		 * @param device 目标UVC设备信息
+		 */
+        public bool CanDraw(UVCManager manager, UVCDevice device)
+        {
+            return UVCFilter.Match(device, UVCFilters);
+        }
+
+        /**
+	     * 已开始获取视频
+         * 实现IUVCdrawer
+         * @param manager 调用方UVCManager
+         * @param device 对象的UVC设备的信息
+         * @param tex 从UVC设备接收视频的纹理实例
+		 */
+        public void OnUVCStartEvent(UVCManager manager, UVCDevice device, Texture tex)
+        {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}OnUVCStartEvent:{device}");
+#endif
+            HandleOnStartPreview(tex);
+            StartPreviewAction?.Invoke(tex);
+        }
+
+        /**
+		 * 视频获取已完成
+         * 实现IUVCdrawer
+         * @param manager 调用方UVCManager
+         * @param device 对象的UVC设备的信息
+		 */
+        public void OnUVCStopEvent(UVCManager manager, UVCDevice device)
+        {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}OnUVCStopEvent:{device}");
+#endif
+            HandleOnStopPreview();
+            StopPreviewAction?.Invoke();
+        }
+
+        //================================================================================
+        /**
+		 * 更新目标
+		 */
+        private void UpdateTarget()
+        {
+            bool found = false;
+            if ((RenderTargets != null) && (RenderTargets.Count > 0))
+            {
+                TargetMaterials = new UnityEngine.Object[RenderTargets.Count];
+                SavedTextures = new Texture[RenderTargets.Count];
+                quaternions = new Quaternion[RenderTargets.Count];
+                int i = 0;
+                foreach (var target in RenderTargets)
+                {
+                    if (target != null)
+                    {
+                        var material = TargetMaterials[i] = GetTargetMaterial(target);
+                        if (material != null)
+                        {
+                            found = true;
+                        }
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+                        Console.WriteLine($"{TAG}UpdateTarget:material={material}");
+#endif
+                    }
+                    i++;
+                }
+            }
+            if (!found)
+            {   //找不到一个目标时,该脚本
+                //尝试从AddComponent GameObject获取
+                //在XXX RenderTargets中设置gameObject?
+                TargetMaterials = new UnityEngine.Object[1];
+                SavedTextures = new Texture[1];
+                quaternions = new Quaternion[1];
+                TargetMaterials[0] = GetTargetMaterial(gameObject);
+                found = TargetMaterials[0] != null;
+            }
+
+            if (!found)
+            {
+                throw new UnityException("no target material found.");
+            }
+        }
+
+        /**
+		* 获取将图像绘制为纹理的材质
+		* 如果指定的GameObject具有Skybox/Render/RawImage/Material,则从中获取Material
+		* 如果每个都分配了多个,则返回第一个找到的可用项
+		* 优先级:Skybox>Render>RawImage>Material
+		* @param target
+		* @return如果找不到,则返回null
+		*/
+        UnityEngine.Object GetTargetMaterial(GameObject target/*NonNull*/)
+        {
+            // Skyboxの取得を試みる
+            var skyboxs = target.GetComponents<Skybox>();
+            if (skyboxs != null)
+            {
+                foreach (var skybox in skyboxs)
+                {
+                    if (skybox.isActiveAndEnabled && (skybox.material != null))
+                    {
+                        RenderSettings.skybox = skybox.material;
+                        return skybox.material;
+                    }
+                }
+            }
+            // Skyboxが取得できなければRendererの取得を試みる
+            var renderers = target.GetComponents<Renderer>();
+            if (renderers != null)
+            {
+                foreach (var renderer in renderers)
+                {
+                    if (renderer.enabled && (renderer.material != null))
+                    {
+                        return renderer.material;
+                    }
+
+                }
+            }
+            // SkyboxもRendererも取得できなければRawImageの取得を試みる
+            var rawImages = target.GetComponents<RawImage>();
+            if (rawImages != null)
+            {
+                foreach (var rawImage in rawImages)
+                {
+                    if (rawImage.enabled && (rawImage.material != null))
+                    {
+                        return rawImage;
+                    }
+
+                }
+            }
+            // SkyboxもRendererもRawImageも取得できなければMaterialの取得を試みる
+            var material = target.GetComponent<Material>();
+            if (material != null)
+            {
+                return material;
+            }
+            return null;
+        }
+
+        private void RestoreTexture()
+        {
+            for (int i = 0; i < TargetMaterials.Length; i++)
+            {
+                var target = TargetMaterials[i];
+                try
+                {
+                    if (target is Material)
+                    {
+                        (target as Material).mainTexture = SavedTextures[i];
+                    }
+                    else if (target is RawImage)
+                    {
+                        (target as RawImage).texture = SavedTextures[i];
+                    }
+                }
+                catch
+                {
+                    Console.WriteLine($"{TAG}RestoreTexture:Exception cought");
+                }
+                SavedTextures[i] = null;
+                quaternions[i] = Quaternion.identity;
+            }
+        }
+
+        private void ClearTextures()
+        {
+            for (int i = 0; i < SavedTextures.Length; i++)
+            {
+                SavedTextures[i] = null;
+            }
+        }
+
+        /**
+		 * 映像取得開始時の処理
+		 * @param tex 映像を受け取るテクスチャ
+		 */
+        private void HandleOnStartPreview(Texture tex)
+        {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}HandleOnStartPreview:({tex})");
+#endif
+            int i = 0;
+            foreach (var target in TargetMaterials)
+            {
+                if (target is Material)
+                {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+                    Console.WriteLine($"{TAG}HandleOnStartPreview:assign Texture to Material({target})");
+#endif
+                    SavedTextures[i++] = (target as Material).mainTexture;
+                    (target as Material).mainTexture = tex;
+                }
+                else if (target is RawImage)
+                {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+                    Console.WriteLine($"{TAG}HandleOnStartPreview:assign Texture to RawImage({target})");
+#endif
+                    SavedTextures[i++] = (target as RawImage).texture;
+                    (target as RawImage).texture = tex;
+                }
+            }
+        }
+
+        /**
+		 * 映像取得が終了したときのUnity側の処理
+		 */
+        private void HandleOnStopPreview()
+        {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}HandleOnStopPreview:");
+#endif
+            // 描画先のテクスチャをもとに戻す
+            RestoreTexture();
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}HandleOnStopPreview:finished");
+#endif
+        }
+
+    } // class UVCDrawer
+
+} // namespace Serenegiant.UVC

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/UVCDrawer.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: efb1bc18f15fa0546b998062ea4861a3
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 300
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 132 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/UVCFilter.cs

@@ -0,0 +1,132 @@
+//#define ENABLE_LOG
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Serenegiant.UVC
+{
+	/**
+	 * UVC機器のフィルタ定義クラス
+	 */
+	[Serializable]
+	public class UVCFilter
+	{
+		private const string TAG = "UVCFilter#";
+
+		/**
+		 * インスペクタでフィルターのコメントを表示するための文字列(スクリプトでは使わない)
+		 */
+		public string Description;
+		/**
+		 * マッチするベンダーID
+		 * 0なら全てにマッチする
+		 */
+		public int Vid;
+		/**
+		 * マッチするプロダクトID
+		 * 0なら全てにマッチする
+		 */
+		public int Pid;
+		/**
+		 * マッチする機器名
+		 * null/emptyならチェックしない
+		 */
+		public string DeviceName;
+		/**
+		 * 除外フィルタとして扱うかどうか
+		 */
+		public bool IsExclude;
+
+		//--------------------------------------------------------------------------------
+
+		/**
+		 * 引数のUVC機器にマッチするかどうかを取得
+		 * @param device
+		 */
+		public bool Match(UVCDevice device)
+		{
+			bool result = device != null;
+
+			if (result)
+			{
+				result &= ((Vid <= 0) || (Vid == device.vid))
+					&& ((Pid <= 0) || (Pid == device.pid))
+					&& (String.IsNullOrEmpty(DeviceName)
+						|| DeviceName.Equals(device.name)
+						|| DeviceName.Equals(device.name)
+						|| (String.IsNullOrEmpty(device.name) || device.name.Contains(DeviceName))
+						|| (String.IsNullOrEmpty(device.name) || device.name.Contains(DeviceName))
+					);
+			}
+
+			return result;
+		}
+
+		//--------------------------------------------------------------------------------
+
+		/**
+		 * UVC機器のフィルタ処理用
+		 * filtersがnullの場合はマッチしたことにする
+		 * 除外フィルターにヒットしたときはその時点で評価を終了しfalseを返す
+		 * 除外フィルターにヒットせず通常フィルターのいずれかにヒットすればtrueを返す
+		 * @param device
+		 * @param filters Nullable
+		 */
+		public static bool Match(UVCDevice device, List<UVCFilter> filters/*Nullable*/)
+		{
+			return Match(device, filters != null ? filters.ToArray() : (null as UVCFilter[]));
+		}
+
+		/**
+		 * UVC機器のフィルタ処理用
+		 * filtersがnullの場合はマッチしたことにする
+		 * 除外フィルターにヒットしたときはその時点で評価を終了しfalseを返す
+		 * 除外フィルターにヒットせず通常フィルターのいずれかにヒットすればtrueを返す
+		 * @param device
+		 * @param filters Nullable
+		 */
+		public static bool Match(UVCDevice device, UVCFilter[] filters/*Nullable*/)
+		{
+			var result = true;
+
+			if ((filters != null) && (filters.Length > 0))
+			{
+				result = false;
+				foreach (var filter in filters)
+				{
+					if (filter != null)
+					{
+						var b = filter.Match(device);
+						if (b && filter.IsExclude)
+						{   // 除外フィルターにヒットしたときはその時点でフィルタ処理を終了
+							result = false;
+							break;
+						}
+						else
+						{   // どれか一つにヒットすればいい
+							result |= b;
+						}
+					}
+					else
+					{
+						// 空フィルターはマッチしたことにする
+						result = true;
+					}
+
+				}
+			}
+
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}Match({device}):result={result}");
+#endif
+			return result;
+		}
+
+	} // class UVCFilter
+
+} // namespace Serenegiant.UVC

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/UVCFilter.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 22d5bc755e86d284aa98f266ba3f10ac
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 813 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/UVCManager.cs

@@ -0,0 +1,813 @@
+#define ENABLE_LOG
+/*
+ * Copyright (c) 2014 - 2022 t_saki@serenegiant.com 
+ */
+
+using AOT;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Threading;
+using UnityEngine;
+
+#if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
+using UnityEngine.Android;
+#endif
+
+namespace Serenegiant.UVC
+{
+    [RequireComponent(typeof(AndroidUtils))]
+	public class UVCManager : MonoBehaviour
+	{
+		private const string TAG = "UVCManager#";
+		private const string FQCN_DETECTOR = "com.serenegiant.usb.DeviceDetectorFragment";
+        private const int FRAME_TYPE_MJPEG = 0x000007;
+        private const int FRAME_TYPE_H264 = 0x000014;
+        private const int FRAME_TYPE_H264_FRAME = 0x030011;
+
+		/**
+		 * 未设置IUVCSElector时
+		 * 或IUVCSElector在选择分辨率时为空
+		 * 返回时的默认分辨率(宽度)
+		*/
+		public Int32 DefaultWidth = 1280;
+		/**
+		 * 未设置IUVCSElector时
+		 * 或IUVCSElector在选择分辨率时为空
+		 * 返回时的默认分辨率(高度)
+		 */
+		public Int32 DefaultHeight = 720;
+		/**
+		 * *与UVC设备协商时
+		 * H.264是否优先协商
+		 * 仅安卓实机有效
+		 * true:	H.264 > MJPEG > YUV
+		 * false:	MJPEG > H.264 > YUV
+		 */
+		public bool PreferH264 = false;
+		/**
+         * 是否在场景渲染之前请求对UVC设备视频纹理进行渲染
+         */
+		public bool RenderBeforeSceneRendering = false;
+
+		/**
+		 * UVC关系的处理程序
+		 */
+		[SerializeField, ComponentRestriction(typeof(IUVCDrawer))]
+		public Component[] UVCDrawers;
+
+		/**
+		 * 保持正在使用的相机信息的保持架类
+		 */
+		public class CameraInfo
+		{
+			internal readonly UVCDevice device;
+			internal Texture previewTexture;
+            internal int frameType;
+			internal Int32 activeId;
+			private Int32 currentWidth;
+			private Int32 currentHeight;
+            private bool isRenderBeforeSceneRendering;
+            private bool isRendering;
+
+			//PC测试用
+			internal CameraInfo(Texture texture)
+			{
+				this.device = null;
+				activeId = 1;
+				previewTexture = texture;
+				SetSize(texture.width, texture.height);
+			}
+			internal CameraInfo(UVCDevice device)
+			{
+				this.device = device;
+			}
+
+			/**
+			 * 機器idを取得
+			 */
+			public Int32 Id{
+				get { return device.id;  }
+			}
+	
+			/**
+			 * 機器名を取得
+			 */
+			public string DeviceName
+			{
+				get { return device.name; }
+			}
+
+			/**
+			 * 获取供应商标识
+			 */
+			public int Vid
+			{
+				get { return device.vid; }
+			}
+
+			/**
+			 * 获取产品标识
+			 */
+			public int Pid
+			{
+				get { return device.pid; }
+			}
+
+			/**
+			 * 映像取得中かどうか
+			 */
+			public bool IsPreviewing
+			{
+				get { return (activeId != 0) && (previewTexture != null); }
+			}
+
+			/**
+			 * 現在の解像度(幅)
+			 * プレビュー中でなければ0
+			 */
+			public Int32 CurrentWidth
+			{
+				get { return currentWidth; }
+			}
+
+			/**
+			 * 現在の解像度(高さ)
+			 * プレビュー中でなければ0
+			 */
+			public Int32 CurrentHeight
+			{
+				get { return currentHeight; }
+			}
+
+			/**
+			 * 2024/01/19 返回一个size
+			 */
+			public Vector2 Size => new Vector2(currentWidth, currentHeight);
+
+
+			/**
+			 * 現在の解像度を変更
+			 * @param width
+			 * @param height
+			 */
+			internal void SetSize(Int32 width, Int32 height)
+			{
+				currentWidth = width;
+				currentHeight = height;
+			}
+
+
+			public Vector2Int IndexToCoord(int i)
+			{
+				var y = i / currentWidth;
+				var x = i % currentWidth;
+				return new Vector2Int(x, y);
+			}
+
+			public int CoordToIndex(int x, int y)
+			{
+				return y * currentWidth + x;
+			}
+
+			public override string ToString()
+			{
+				return $"{base.ToString()}({currentWidth}x{currentHeight},id={Id},activeId={activeId},IsPreviewing={IsPreviewing})";
+			}
+
+			/**
+             * 开始从UVC设备渲染视频
+             * @param manager
+             */
+			internal Coroutine StartRender(UVCManager manager, bool renderBeforeSceneRendering)
+            {
+                StopRender(manager);
+                isRenderBeforeSceneRendering = renderBeforeSceneRendering;
+                isRendering = true;
+                if (renderBeforeSceneRendering)
+                {
+                    return manager.StartCoroutine(OnRenderBeforeSceneRendering());
+                } else
+                {
+                    return manager.StartCoroutine(OnRender());
+                }
+            }
+
+			/**
+             * 完成UVC设备的视频渲染
+             * @param manager
+             */
+			internal void StopRender(UVCManager manager)
+            {
+                if (isRendering)
+                {
+                    isRendering = false;
+                    if (isRenderBeforeSceneRendering)
+                    {
+                        manager.StopCoroutine(OnRenderBeforeSceneRendering());
+                    }
+                    else
+                    {
+                        manager.StopCoroutine(OnRender());
+                    }
+                }
+            }
+
+			/**
+			 * 用于渲染事件处理
+			 * 作为代码例程执行
+			 * 在场景渲染之前,请求将UVC设备的视频渲染到纹理
+			 */
+			private IEnumerator OnRenderBeforeSceneRendering()
+			{
+				var renderEventFunc = GetRenderEventFunc();
+				for (; activeId != 0;)
+				{
+					yield return null;
+					GL.IssuePluginEvent(renderEventFunc, activeId);
+				}
+				yield break;
+			}
+
+			/**
+             * 用于渲染事件处理
+			 * 作为代码例程执行
+			 * 渲染后请求将UVC设备的视频渲染到纹理
+             */
+			private IEnumerator OnRender()
+            {
+                var renderEventFunc = GetRenderEventFunc();
+                for (; activeId != 0;)
+                {
+                    yield return new WaitForEndOfFrame();
+                    GL.IssuePluginEvent(renderEventFunc, activeId);
+                }
+                yield break;
+            }
+
+        }
+
+		/**
+		 * 用于在主线程上运行的同步上下文实例
+		 */
+		private SynchronizationContext mainContext;
+		/**
+		 * 当连接到终端的UVC设备的状态发生变化时,接受事件回调的分配器
+		 */
+		private OnDeviceChangedCallbackManager.OnDeviceChangedFunc callback;
+		/**
+		 * 连接到终端的UVC设备列表
+		 */
+		private List<UVCDevice> attachedDevices = new List<UVCDevice>();
+		/**
+		 * 正在获取视频的UVC设备的地图
+		 * 保留设备标识的id-CameraInfo对
+		 */
+		private Dictionary<Int32, CameraInfo> cameraInfos = new Dictionary<int, CameraInfo>();
+
+		//--------------------------------------------------------------------------------
+		// 从UnityEngine调用
+		//--------------------------------------------------------------------------------
+		// Start is called before the first frame update
+		IEnumerator Start()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}Start:");
+#endif
+			mainContext = SynchronizationContext.Current;
+            callback = OnDeviceChangedCallbackManager.Add(this);
+	
+			yield return Initialize();
+		}
+
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+		void OnApplicationFocus()
+		{
+			Console.WriteLine($"{TAG}OnApplicationFocus:");
+		}
+#endif
+
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+		void OnApplicationPause(bool pauseStatus)
+		{
+			Console.WriteLine($"{TAG}OnApplicationPause:{pauseStatus}");
+		}
+#endif
+
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+		void OnApplicationQuits()
+		{
+			Console.WriteLine($"{TAG}OnApplicationQuits:");
+		}
+#endif
+
+		void OnDestroy()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}OnDestroy:");
+#endif
+			StopAll();
+            OnDeviceChangedCallbackManager.Remove(this);
+		}
+
+		//--------------------------------------------------------------------------------
+		// UVC设备连接状态变化时插件的回调函数
+		//--------------------------------------------------------------------------------
+		public void OnDeviceChanged(IntPtr devicePtr, bool attached)
+        {
+            var id = UVCDevice.GetId(devicePtr);
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG}OnDeviceChangedInternal:id={id},attached={attached}");
+#endif
+            if (attached)
+            {
+                UVCDevice device = new UVCDevice(devicePtr);
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+                Console.WriteLine($"{TAG}OnDeviceChangedInternal:device={device.ToString()}");
+#endif
+                if (HandleOnAttachEvent(device))
+                {
+                    attachedDevices.Add(device);
+                    StartPreview(device);
+                }
+            }
+            else
+            {
+                var found = attachedDevices.Find(item =>
+                {
+                    return item != null && item.id == id;
+                });
+                if (found != null)
+                {
+                    HandleOnDetachEvent(found);
+                    StopPreview(found);
+                    attachedDevices.Remove(found);
+                }
+            }
+        }
+   
+        //================================================================================
+        /**
+		 * 接続中のUVC機器一覧を取得
+		 * @return 接続中のUVC機器一覧List
+		 */
+        public List<CameraInfo> GetAttachedDevices()
+		{
+			var result = new List<CameraInfo>(cameraInfos.Count);
+
+			foreach (var info in cameraInfos.Values)
+			{
+				result.Add(info);
+			}
+
+			return result;
+		}
+
+//		/**
+//		 * 対応解像度を取得
+//		 * @param camera 対応解像度を取得するUVC機器を指定
+//		 * @return 対応解像度 既にカメラが取り外されている/closeしているのであればnull
+//		 */
+//		public SupportedFormats GetSupportedVideoSize(CameraInfo camera)
+//		{
+//			var info = (camera != null) ? Get(camera.DeviceName) : null;
+//			if ((info != null) && info.IsOpen)
+//			{
+//				return GetSupportedVideoSize(info.DeviceName);
+//			}
+//			else
+//			{
+//				return null;
+//			}
+//		}
+
+//		/**
+//		 * 解像度を変更
+//		 * @param 解像度を変更するUVC機器を指定
+//		 * @param 変更する解像度を指定, nullならデフォルトに戻す
+//		 * @param 解像度が変更されたかどうか
+//		 */
+//		public bool SetVideoSize(CameraInfo camera, SupportedFormats.Size size)
+//		{
+//			var info = (camera != null) ? Get(camera.DeviceName) : null;
+//			var width = size != null ? size.Width : DefaultWidth;
+//			var height = size != null ? size.Height : DefaultHeight;
+//			if ((info != null) && info.IsPreviewing)
+//			{
+//				if ((width != info.CurrentWidth) || (height != info.CurrentHeight))
+//				{   // 解像度が変更になるとき
+//					StopPreview(info.DeviceName);
+//					StartPreview(info.DeviceName, width, height);
+//					return true;
+//				}
+//			}
+//			return false;
+//		}
+
+		private void StartPreview(UVCDevice device)
+		{
+			var info = CreateIfNotExist(device);
+			if ((info != null) && !info.IsPreviewing) {
+
+				int width = DefaultWidth;
+				int height = DefaultHeight;
+
+//				var supportedVideoSize = GetSupportedVideoSize(deviceName);
+//				if (supportedVideoSize == null)
+//				{
+//					throw new ArgumentException("fauled to get supported video size");
+//				}
+
+//				// 解像度の選択処理
+//				if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
+//				{
+//					foreach (var drawer in UVCDrawers)
+//					{
+//						if ((drawer is IUVCDrawer) && ((drawer as IUVCDrawer).CanDraw(this, info.device)))
+//						{
+//							var size = (drawer as IUVCDrawer).OnUVCSelectSize(this, info.device, supportedVideoSize);
+//#if (!NDEBUG && DEBUG && ENABLE_LOG)
+//							Console.WriteLine($"{TAG}StartPreview:selected={size}");
+//#endif
+//							if (size != null)
+//							{   // 一番最初に見つかった描画可能なIUVCDrawersがnull以外を返せばそれを使う
+//								width = size.Width;
+//								height = size.Height;
+//								break;
+//							}
+//						}
+//					}
+//				}
+
+				// FIXME 対応解像度の確認処理
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+				Console.WriteLine($"{TAG}StartPreview:({width}x{height}),id={device.id}");
+#endif
+                int[] frameTypes = {
+                    PreferH264 ? FRAME_TYPE_H264 : FRAME_TYPE_MJPEG,
+                    PreferH264 ? FRAME_TYPE_MJPEG : FRAME_TYPE_H264,
+                };
+                foreach (var frameType in frameTypes)
+                {
+                    if (Resize(device.id, frameType, width, height) == 0)
+                    {
+                        info.frameType = frameType;
+                        break;
+                    }
+                }
+                    
+				info.SetSize(width, height);
+				info.activeId = device.id;
+				mainContext.Post(__ =>
+				{   // 必须在主线程上生成纹理
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+					Console.WriteLine($"{TAG}影像接收用纹理生成:({width}x{height})");
+#endif
+					Texture2D tex = new Texture2D(
+							width, height,
+							TextureFormat.ARGB32,
+							false, /* mipmap */
+							true /* linear */);
+					tex.filterMode = FilterMode.Point;
+					tex.Apply();
+					info.previewTexture = tex;
+					var nativeTexPtr = info.previewTexture.GetNativeTexturePtr();
+					Start(device.id, nativeTexPtr.ToInt32());
+					HandleOnStartPreviewEvent(info);
+					info.StartRender(this, RenderBeforeSceneRendering);
+				}, null);
+			}
+		}
+
+		private void StopPreview(UVCDevice device) {
+			var info = Get(device);
+			if ((info != null) && info.IsPreviewing)
+			{
+				mainContext.Post(__ =>
+				{
+					HandleOnStopPreviewEvent(info);
+					Stop(device.id);
+					info.StopRender(this);
+					info.SetSize(0, 0);
+					info.activeId = 0;
+				}, null);
+			}
+		}
+
+
+		private void StopAll() {
+			List<CameraInfo> values = new List<CameraInfo>(cameraInfos.Values);
+			foreach (var info in values)
+			{
+				StopPreview(info.device);
+			}
+		}
+
+		//--------------------------------------------------------------------------------
+		/**
+		 * 连接UVC设备时的处理实体
+		 * @param info
+		 * @return true: 使用连接的UVC设备, false: 不使用连接的UVC设备 
+		 */
+		private bool HandleOnAttachEvent(UVCDevice device/*NonNull*/)
+		{
+			if ((UVCDrawers == null) || (UVCDrawers.Length == 0))
+			{   // IUVCDrawerが割り当てられていないときはtrue(接続されたUVC機器を使用する)を返す
+				return true;
+			}
+			else
+			{
+				bool hasDrawer = false;
+				foreach (var drawer in UVCDrawers)
+				{
+					if (drawer is IUVCDrawer)
+					{
+						hasDrawer = true;
+						if ((drawer as IUVCDrawer).OnUVCAttachEvent(this, device))
+						{   // どれか1つのIUVCDrawerがtrueを返せばtrue(接続されたUVC機器を使用する)を返す
+							return true;
+						}
+					}
+				}
+				// IUVCDrawerが割り当てられていないときはtrue(接続されたUVC機器を使用する)を返す
+				return !hasDrawer;
+			}
+		}
+
+		/**
+		 * UVC设备被拆除时的处理实体
+		 * @param info
+		 */
+		private void HandleOnDetachEvent(UVCDevice device/*NonNull*/)
+		{
+			if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
+			{
+				foreach (var drawer in UVCDrawers)
+				{
+					if (drawer is IUVCDrawer)
+					{
+						(drawer as IUVCDrawer).OnUVCDetachEvent(this, device);
+					}
+				}
+			}
+		}
+
+		/**
+		 * 从UVC机器的影像取得结束
+		 * @param args UVC機器の識別文字列
+		 */
+		void HandleOnStartPreviewEvent(CameraInfo info)
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:({info})");
+#endif
+			if ((info != null) && info.IsPreviewing && (UVCDrawers != null))
+			{
+				foreach (var drawer in UVCDrawers)
+				{
+					if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).CanDraw(this, info.device))
+					{
+						(drawer as IUVCDrawer).OnUVCStartEvent(this, info.device, info.previewTexture);
+					}
+				}
+			} else {
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+				Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:No UVCDrawers");
+#endif
+			}
+		}
+
+		/**
+		 * UVC機器からの映像取得を終了した
+		 * @param args UVC機器の識別文字列
+		 */
+		void HandleOnStopPreviewEvent(CameraInfo info)
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}HandleOnStopPreviewEvent:({info})");
+#endif
+			if (UVCDrawers != null)
+			{
+				foreach (var drawer in UVCDrawers)
+				{
+					if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).CanDraw(this, info.device))
+					{
+						(drawer as IUVCDrawer).OnUVCStopEvent(this, info.device);
+					}
+				}
+			}
+		}
+
+		//--------------------------------------------------------------------------------
+		/**
+		 * 获取与指定UVC标识字符串相对应的CameraInfo
+		 * 如果尚未注册,则新建
+		 * @param deviceName UVC機器識別文字列
+		 * @param CameraInfoを返す
+		 */
+		/*NonNull*/
+		private CameraInfo CreateIfNotExist(UVCDevice device)
+		{
+			if (!cameraInfos.ContainsKey(device.id))
+			{
+				cameraInfos[device.id] = new CameraInfo(device);
+			}
+			return cameraInfos[device.id];
+		}
+
+		/**
+		 * 获取与指定UVC标识字符串相对应的CameraInfo
+		 * @param deviceName UVC机器识别文字列
+		 * @param 注册时返回CameraInfo,未注册时为空
+		 */
+		/*Nullable*/
+		private CameraInfo Get(UVCDevice device)
+		{
+			return cameraInfos.ContainsKey(device.id) ? cameraInfos[device.id] : null;
+		}
+
+
+		//--------------------------------------------------------------------------------
+		/**
+		 *初始化插件
+		 *如果确认并获取权限,则调用实际的插件初始化处理#InitPlugin
+		 */
+		private IEnumerator Initialize()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}Initialize:");
+#endif
+			if (AndroidUtils.CheckAndroidVersion(28))
+			{
+				yield return AndroidUtils.GrantCameraPermission((string permission, AndroidUtils.PermissionGrantResult result) =>
+				{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+					Console.WriteLine($"{TAG}OnPermission:{permission}={result}");
+#endif
+					switch (result)
+					{
+						case AndroidUtils.PermissionGrantResult.PERMISSION_GRANT:
+							InitPlugin();
+							break;
+						case AndroidUtils.PermissionGrantResult.PERMISSION_DENY:
+							if (AndroidUtils.ShouldShowRequestPermissionRationale(AndroidUtils.PERMISSION_CAMERA))
+							{
+								//无法获得权限
+								//必须显示FIXME说明用的对话框等
+							}
+							break;
+						case AndroidUtils.PermissionGrantResult.PERMISSION_DENY_AND_NEVER_ASK_AGAIN:
+							break;
+					}
+				});
+			}
+			else
+			{
+				InitPlugin();
+			}
+
+			yield break;
+		}
+
+		/**
+		 * 初始化插件
+		 * 对uvc-plugin-unity的处理请求
+		 */
+		private void InitPlugin()
+		{
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}InitPlugin:");
+#endif
+			// 检查是否分配了IUVCdrawers
+			var hasDrawer = false;
+			if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
+			{
+				foreach (var drawer in UVCDrawers)
+				{
+					if (drawer is IUVCDrawer)
+					{
+						hasDrawer = true;
+						break;
+					}
+				}
+			}
+			if (!hasDrawer)
+			{   
+				//在检查器中未设置IUVCdrawer时
+				//尝试从带有此脚本的游戏对象获取
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+				Console.WriteLine($"{TAG}InitPlugin:has no IUVCDrawer, try to get from gameObject");
+#endif
+				var drawers = GetComponents(typeof(IUVCDrawer));
+				if ((drawers != null) && (drawers.Length > 0))
+				{
+					UVCDrawers = new Component[drawers.Length];
+					int i = 0;
+					foreach (var drawer in drawers)
+					{
+						UVCDrawers[i++] = drawer;
+					}
+				}
+			}
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+			Console.WriteLine($"{TAG}InitPlugin:num drawers={UVCDrawers.Length}");
+#endif
+			// 请求读取aandusb的DeviceDetector
+			using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_DETECTOR))
+			{
+				clazz.CallStatic("initUVCDeviceDetector",
+					AndroidUtils.GetCurrentActivity());
+			}
+		}
+
+		//--------------------------------------------------------------------------------
+		// 定义和声明本机插件关系
+		//--------------------------------------------------------------------------------
+		/**
+		 * 插件中的渲染事件获取native(c/c++)函数
+		 */
+		[DllImport("unityuvcplugin")]
+		private static extern IntPtr GetRenderEventFunc();
+        /**
+		 * 初期設定
+		 */
+        [DllImport("unityuvcplugin", EntryPoint = "Config")]
+        private static extern Int32 Config(Int32 deviceId, Int32 enabled, Int32 useFirstConfig);
+        /**
+		 * 映像取得開始
+		 */
+        [DllImport("unityuvcplugin", EntryPoint ="Start")]
+		private static extern Int32 Start(Int32 deviceId, Int32 tex);
+		/**
+		 * 映像取得終了
+		 */
+		[DllImport("unityuvcplugin", EntryPoint ="Stop")]
+		private static extern Int32 Stop(Int32 deviceId);
+		/**
+		 * 影像尺寸设定
+		 */
+		[DllImport("unityuvcplugin")]
+		private static extern Int32 Resize(Int32 deviceId, Int32 frameType, Int32 width, Int32 height);
+	}   // UVCManager
+
+	/**
+	*如果是IL2Cpp的话,就不能对用于从c/c++回调的引导者进行跟踪
+	*必须使用static类函数进行处理。
+	*但如果是这样,则无法调用调用对象的函数,因此创建管理器类
+	*首先只接受UVCmanager,所以不作为接口
+     */
+	public static class OnDeviceChangedCallbackManager
+    {
+        //コールバック関数の型を宣言
+        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+        public delegate void OnDeviceChangedFunc(Int32 id, IntPtr devicePtr, bool attached);
+
+        /**
+		 * プラグインのnative側登録関数
+		 */
+        [DllImport("unityuvcplugin")]
+        private static extern IntPtr Register(Int32 id, OnDeviceChangedFunc callback);
+        /**
+		 * プラグインのnative側登録解除関数
+		 */
+        [DllImport("unityuvcplugin")]
+        private static extern IntPtr Unregister(Int32 id);
+
+        private static Dictionary<Int32, UVCManager> sManagers = new Dictionary<Int32, UVCManager>();
+  
+        /**
+         * 指定したUVCManagerを接続機器変化コールバックに追加
+         */
+        public static OnDeviceChangedFunc Add(UVCManager manager)
+        {
+            Int32 id = manager.GetHashCode();
+            OnDeviceChangedFunc callback = new OnDeviceChangedFunc(OnDeviceChanged);
+            sManagers.Add(id, manager);
+            Register(id, callback);
+            return callback;
+        }
+
+        /**
+         * 指定したUVCManagerを接続機器変化コールバックから削除
+         */
+        public static void Remove(UVCManager manager)
+        {
+            Int32 id = manager.GetHashCode();
+            Unregister(id);
+            sManagers.Remove(id);
+        }
+
+        [MonoPInvokeCallback(typeof(OnDeviceChangedFunc))]
+        public static void OnDeviceChanged(Int32 id, IntPtr devicePtr, bool attached)
+        {
+            var manager = sManagers.ContainsKey(id) ? sManagers[id] : null;
+            if (manager != null)
+            {
+                manager.OnDeviceChanged(devicePtr, attached);
+            }
+        }
+    } // OnDeviceChangedCallbackManager
+
+
+}   // namespace Serenegiant.UVC

+ 11 - 0
Assets/UVC4UnityAndroidPlugin/Scripts/UVCManager.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f7e3fa0f7bdc68444abad301469f7cf7
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/WebCamera.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 600ee4be6a195644db3f1b68b2f0a379
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/WebCamera/Image.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 23e7f6fdb0f60e64899c48cb78050b99
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/WebCamera/Image/crosshair2.png


+ 123 - 0
Assets/WebCamera/Image/crosshair2.png.meta

@@ -0,0 +1,123 @@
+fileFormatVersion: 2
+guid: 24d1e577dc42aaf4ba6e64be26be3845
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  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
+  vTOnly: 0
+  ignoreMasterTextureLimit: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 0
+    wrapV: 0
+    wrapW: 0
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  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: 0
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  singleChannelComponent: 0
+  flipbookRows: 1
+  flipbookColumns: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  ignorePngGamma: 0
+  applyGammaDecoding: 0
+  cookieLightType: 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: 0
+  - 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: 0
+  - serializedVersion: 3
+    buildTarget: Server
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+    nameFileIdTable: {}
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/WebCamera/Script.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 784d1e90542fffa46aba4cac2d36a9f6
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/WebCamera/Script/ZIM.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 97eed322e5db5404abf2c77d6afd036b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d3186d7f35e4a5347a2ddcc16d76d286
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 732 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredLocate.cs

@@ -0,0 +1,732 @@
+using o0;
+using o0.Project;
+using SixLabors.ImageSharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization.Formatters;
+using System.Threading.Tasks;
+using UnityEngine;
+using ZIM.Unity;
+using Color = UnityEngine.Color;
+using Debug = UnityEngine.Debug;
+
+namespace ZIM
+{
+    //class DescendingComparer<T> : IComparer<T>
+    //{
+    //    public int Compare(T x, T y)
+    //    {
+    //        return Comparer<T>.Default.Compare(y, x);
+    //    }
+    //}
+
+    public enum InfraredMatch
+    {
+        Nomatch = 0,
+        Match0 = 1,
+        Match1 = 2
+    }
+
+    // 支持2个红外点的识别
+    public class InfraredLocate
+    {
+        public static object locker = new object();
+
+        public static List<InfraredMatch> GetMatches(InfraredMatch im)
+        {
+            List<InfraredMatch> positions = new List<InfraredMatch>();
+            InfraredMatch bit = InfraredMatch.Match0;
+            while (bit <= im)
+            {
+                if ((im & bit) != 0)
+                {
+                    positions.Add(bit);
+                }
+                bit = (InfraredMatch)((int)bit << 1);
+            }
+            return positions;
+        }
+
+        readonly int samplingScale = 2;
+        readonly float[] spotBrightness = new float[] { 0.93f, 0.5f };      // 亮点阈值
+        //const float circleVariance = 30f;
+        //const int brightAreaRadius = 30; 
+        //const int LeastBrightPoint = 10000;
+
+        Serenegiant.UVC.UVCManager.CameraInfo mCameraInfo;
+        ScreenIdentification screenIdentification;
+        InfraredSpotSettings infraredSpotSettings;
+
+        InfraredSpot[] InfraredSpots;
+        public InfraredSpot GetSpot(InfraredMatch match)
+        {
+            switch (match)
+            {
+                case InfraredMatch.Match0:
+                    return InfraredSpots[0];
+                case InfraredMatch.Match1:
+                    return InfraredSpots[1];
+                default:
+                    return null;
+            }
+        }
+
+        public InfraredLocate(Serenegiant.UVC.UVCManager.CameraInfo cameraInfo, ScreenIdentification infraredIdentification, InfraredSpotSettings infraredSpotSettings)
+        {
+            this.mCameraInfo = cameraInfo;
+            this.screenIdentification = infraredIdentification;
+            this.infraredSpotSettings = infraredSpotSettings;
+        }
+
+        readonly int CheakFrame = 10;
+
+        bool Infrared12Overlap = false;
+        int cheakCounter = 0;
+
+        public InfraredSpot[] UpdateSingle(Color[] cameraPixels)
+        {
+            var spotArea = LocateToScreen(cameraPixels, screenIdentification.Screen.QuadRect);
+            if (spotArea.Count > 0)
+            {
+                InfraredSpots[0].Update(spotArea.Max((a, b) => a.Radius.CompareTo(b.Radius)));
+            }
+            return InfraredSpots;
+        }
+
+        // New, 通过透视映射计算红外点的相对位置, 返回的红外点根据半径 从大到小排序
+        public InfraredSpot[] Update(Color[] cameraPixels)
+        {
+            var spotArea = LocateToScreen(cameraPixels, screenIdentification.Screen.QuadRect);
+            return MatchInfraredRay(spotArea);
+        }
+
+        // New, 返回由大到小排序的点
+        public List<PixelSpotArea> LocateToScreen(Color[] pixels, Rect rect)
+        {
+            if (InfraredSpots == null)
+            {
+                InfraredSpots = new InfraredSpot[2] {
+                new InfraredSpot(screenIdentification.Screen, InfraredMatch.Match0),
+                new InfraredSpot(screenIdentification.Screen, InfraredMatch.Match1) };
+            }
+
+            //var watch = new System.Diagnostics.Stopwatch();
+            //watch.Start();
+            //var times = new List<double>() { 0.0 };
+
+            /* 根据亮点情况调整samplingScale
+
+            (int x, int y) rectMin = ((int)rect.min.x / samplingScale, (int)rect.min.y / samplingScale);
+            (int x, int y) rectMax = ((int)rect.max.x / samplingScale, (int)rect.max.y / samplingScale);
+            int brightCount = 0;
+            Parallel.For(rectMin.x, rectMax.x, (i) =>
+            {
+                for (int j = rectMin.y; j < rectMax.y; j++)
+                {
+                    int ip = i * samplingScale;
+                    int jp = j * samplingScale;
+                    var index = camera.Vector2ToIndex(ip, jp);
+                    var b = pixels[index].Brightness(64);
+
+                    if (b > minBrightness)
+                    {
+                        lock (locker)
+                        {
+                            brightCount++;
+                        }
+                    }
+                }
+            });
+            if (brightCount > 1000)
+            {
+                samplingScale = (int)Math.Ceiling(samplingScale * Math.Sqrt(brightCount / 1000.0));       // 如果亮点太多,控制亮点数量在1000左右
+            }
+            /**/
+
+            (int x, int y) rectMin = ((int)rect.min.x / samplingScale, (int)rect.min.y / samplingScale);
+            (int x, int y) rectMax = ((int)rect.max.x / samplingScale, (int)rect.max.y / samplingScale);
+
+            var spotPoint = new List<Vector2>((int)rect.width * (int)rect.height / 256);     // 预估的初始容量
+            var brightPoint = new List<Vector2>((int)rect.width * (int)rect.height / 64);
+
+            Parallel.For(rectMin.x, rectMax.x, (i) =>
+            {
+                var points0 = new List<Vector2>(rectMax.y - rectMin.y);
+                var points1 = new List<Vector2>(rectMax.y - rectMin.y);
+                for (int j = rectMin.y; j < rectMax.y; j++)
+                {
+                    int ip = i * samplingScale;
+                    int jp = j * samplingScale;
+                    var index = mCameraInfo.CoordToIndex(ip, jp);
+                    //var b = brightness[index];
+                    //var b = (int)Math.Round(ConvBrightness(brightness, (ip, jp)));
+                    var b = pixels[index].Brightness();
+
+                    if (b > spotBrightness[0])
+                    {
+                        points0.Add(new Vector2(ip, jp));
+                    }
+                    else if (b > spotBrightness[1])
+                    {
+                        points1.Add(new Vector2(ip, jp));
+                    }
+                }
+                lock (spotPoint)
+                {
+                    spotPoint.AddRange(points0);
+                    brightPoint.AddRange(points1);
+                }
+            });
+            //Debug.Log("spotPoint Count: " + spotPoint.Count + ", brightPoint Count: " + brightPoint.Count);
+
+            //times.Add(watch.ElapsedMilliseconds);
+            //UnityEngine.Debug.Log("time1: " + (times[times.Count - 1] - times[times.Count - 2]));
+
+            // 所有点映射到屏幕空间
+            Parallel.For(0, spotPoint.Count, (i) => spotPoint[i] = screenIdentification.Screen.TransformToScreen(spotPoint[i]));
+            Parallel.For(0, brightPoint.Count, (i) => brightPoint[i] = screenIdentification.Screen.TransformToScreen(brightPoint[i]));
+
+            //{
+            //    var texure = new Texture2D((int)screenIdentification.Screen.UVSize.x + 1, (int)screenIdentification.Screen.UVSize.y + 1);
+            //    var pixels2 = new Color[texure.width * texure.height];
+            //    foreach (var i in pixels2.Index())
+            //        pixels2[i] = Color.white;
+
+            //    foreach (var i in spotPoint)
+            //    {
+            //        if (!screenIdentification.Screen.UVInScreen(i))
+            //            continue;
+            //        pixels2[(int)i.y * texure.width + (int)i.x] = Color.red;
+            //    }
+            //    foreach (var i in brightPoint)
+            //    {
+            //        if (!screenIdentification.Screen.UVInScreen(i))
+            //            continue;
+            //        pixels2[(int)i.y * texure.width + (int)i.x] = Color.black;
+            //    }
+            //    texure.filterMode = FilterMode.Point;
+            //    texure.SetPixels(pixels2);
+            //    texure.Apply();
+            //    ScreenLocate.DebugTexture(2, texure);
+            //}
+
+            if (spotPoint.Count > 0)
+            {
+                //times.Add(watch.ElapsedMilliseconds);
+                //UnityEngine.Debug.Log("time2: " + (times[times.Count - 1] - times[times.Count - 2]));
+
+                var spotArea = PixelSpotArea.Cluster(spotPoint, brightPoint, screenIdentification.Screen.UVInScreen);
+
+                //times.Add(watch.ElapsedMilliseconds);
+                //UnityEngine.Debug.Log("time3: " + (times[times.Count - 1] - times[times.Count - 2]));
+
+                if (spotArea.Count == 0)
+                    return spotArea;
+
+                // 亮度较低的部分合并到区域中
+                for (int i = 0; i < brightPoint.Count; i++)
+                {
+                    var p = brightPoint[i];
+                    var grid = PixelSpotArea.GetGrid1(p);
+                    for (int j = 0; j < spotArea.Count; j++)
+                    {
+                        var area = spotArea[j];
+                        if (area.Include1(grid))
+                            area.Add(p);
+                    }
+                }
+
+                //Debug.Log("Area Count" + spotArea.Count);
+
+                //times.Add(watch.ElapsedMilliseconds);
+                //UnityEngine.Debug.Log("time4: " + (times[times.Count - 1] - times[times.Count - 2]));
+
+                return spotArea;
+
+                //半径再按透视修正一遍,降低一点常规角度下反射的影响
+                foreach (var i in spotArea)
+                {
+                    var r0 = i.Radius / 2 / mCameraInfo.CurrentWidth;
+                    var center = i.Center;
+                    var offset1 = center + new Vector2(i.Radius / 2, 0);
+                    var offset2 = center - new Vector2(i.Radius / 2, 0);
+                    var offset3 = center + new Vector2(0, i.Radius / 2);
+                    var offset4 = center - new Vector2(0, i.Radius / 2);
+                    var transR = ((screenIdentification.Screen.TransformToScreen(offset1) - screenIdentification.Screen.TransformToScreen(offset2)).magnitude +
+                        (screenIdentification.Screen.TransformToScreen(offset3) - screenIdentification.Screen.TransformToScreen(offset4)).magnitude) / 4;
+                    var r1 = transR / screenIdentification.Screen.UVSize.x;
+                    //Debug.Log(r1 / r0);
+                    i.Radius *= (float)Math.Pow(r1 / r0, 2);      // 摄像机位置不同参数也可能不同
+                }
+
+                //if (spotArea.Count == 1)
+                //Debug.Log($"{spotArea[0].MaxRadius}");
+
+                return spotArea;
+
+                //// 排序亮区
+                //spotArea.Sort((a, b) => b.MaxRadius.CompareTo(a.MaxRadius));
+                ////var areas = new SortedList<float, PixelSpotArea>(new DescendingComparer<float>());
+                ////foreach (var i in spotArea)
+                ////    areas.Add(i.MaxRadius, i);
+
+                //var result = new Vector2[spotArea.Count];
+                //foreach (var i in spotArea.Index())
+                //    result[i] = spotArea[i].Center;
+
+                //times.Add(watch.ElapsedMilliseconds);
+                //UnityEngine.Debug.Log("time6: " + (times[times.Count - 1] - times[times.Count - 2]));
+
+                //return result;
+            }
+
+            return new List<PixelSpotArea>();
+        }
+
+        public List<Vector2> GetOld(int[] brightness)        // 取整后的亮度图
+        {
+            return LocateOld(brightness, new Rect(0, 0, mCameraInfo.CurrentWidth, mCameraInfo.CurrentHeight));
+        }
+        public List<Vector2> LocateOld(int[] brightness, Rect rect)
+        {
+            var brightPixelDic = new Dictionary<float, List<Vector2>>();
+            (int x, int y) origin = ((int)rect.min.x + 1, (int)rect.min.y + 1);
+            Parallel.For(origin.x / samplingScale, (origin.x + (int)rect.width) / samplingScale, (i) =>
+            {
+                for (int j = origin.y / samplingScale; j < (origin.y + rect.height) / samplingScale; j++)
+                {
+                    int ip = i * samplingScale;
+                    int jp = j * samplingScale;
+                    var index = mCameraInfo.CoordToIndex(ip, jp);
+                    //var b = brightness[index];
+                    //var b = (int)Math.Round(ConvBrightness(brightness, (ip, jp)));
+                    var b = ConvBrightness(brightness, (ip, jp), 3);
+
+                    if (b > 32)
+                    {
+                        lock (brightPixelDic)
+                        {
+                            if (brightPixelDic.TryGetValue(b, out List<Vector2> list))
+                                list.Add(new Vector2(ip, jp));
+                            else
+                                brightPixelDic.Add(b, new List<Vector2> { new Vector2(ip, jp) });
+                        }
+                    }
+                }
+            });
+
+            //Parallel.For(0, pixels.Length / 7, (i) =>
+            //{
+            //    i = i * 7;
+            //    var b = getBrightness(pixels[i]);
+            //    if (b >= maxBrightness)
+            //    {
+            //        lock (brightSpots)
+            //        {
+            //            if (b != maxBrightness)
+            //                brightSpots.Clear();
+            //            brightSpots.Add(indexToVector2(i));
+            //        }
+            //        maxBrightness = b;
+            //    }
+            //});
+
+            if (brightPixelDic.Count > 0)
+            {
+                // 取亮度最高的像素
+                var keys = brightPixelDic.Keys.ToList();
+                var maxIndex = o0.o0.MaxIndex(keys);
+                //keys.Sort((a, b) => -a.CompareTo(b));
+                var brightPixels = new List<Vector2>();
+                for (int i = 0; i < Math.Min(1, keys.Count); i++)
+                    brightPixels.AddRange(brightPixelDic[keys[maxIndex]]);
+
+                //Debug.Log("max brightness: " + keys[maxIndex]);
+                //Debug.Log("brightPixels.Count: " + brightPixels.Count);
+
+                //var testTexture = new Texture2D((int)_textureSize.x, (int)_textureSize.y);
+                //testTexture.wrapMode = TextureWrapMode.Clamp;
+                //testTexture.filterMode = FilterMode.Point;
+                //foreach (var i in brightPixels)
+                //    testTexture.SetPixel((int)i.x, (int)i.y, Color.black);
+                //testTexture.Apply();
+                //testImage.texture = testTexture;
+
+                var brightArea = new List<PixelCircleArea>() { new PixelCircleArea(brightPixels.First()) };
+                for (int i = 1; i < brightPixels.Count; i++)
+                {
+                    var p = brightPixels[i];
+                    var grid = PixelArea.GetGrid(p);
+                    var join = new SortedList<int, PixelCircleArea>();
+                    for (int j = 0; j < brightArea.Count; j++)
+                    {
+                        var area = brightArea[j];
+                        if (area.Include(grid))
+                            join.Add(j, area);
+                    }
+                    if (join.Count == 0)
+                        brightArea.Add(new PixelCircleArea(p));
+                    else if (join.Count == 1)
+                        join.First().Value.Add(p, grid);
+                    else
+                    {
+                        var combine = new PixelCircleArea(join.Values);
+                        combine.Add(p, grid);
+                        brightArea.Add(combine);
+                        for (int j = join.Count - 1; j >= 0; j--)
+                            brightArea.RemoveAt(join.ElementAt(j).Key);
+                    }
+
+                    //foreach (var j in brightArea)
+                    //{
+                    //    var offset = (p - j.Center);
+                    //    if (offset.magnitude < brightAreaRadius)     // 距离近的并入该区域
+                    //    {
+                    //        j.Pixels.Add(p);
+                    //        j.Center += offset / j.Pixels.Count;
+                    //        join = true;
+                    //        break;
+                    //    }
+                    //}
+                    //if (!join)
+                    //    brightArea.Add(new PixelArea(p));
+                }
+
+                //var sum = new Vector2(0, 0);
+                //foreach (var i in brightPixels)
+                //{
+                //    sum += i;
+                //}
+                //var middle = sum/brightPixels.Count;
+                //Debug.Log("brightArea.Count: " + brightArea.Count);
+
+                //if (brightArea.Count <= 1)
+                //    return brightArea.FirstOrDefault().Center;
+
+                //PixelArea maxBrightArea = brightArea.First();
+                //float maxCircleBrightness = 10000f;
+                var CircleAreas = new List<PixelCircleArea>();
+
+                for (int i = 0; i < brightArea.Count; i++)
+                {
+                    var area = brightArea[i];
+                    var value = area.CircleBrightness(out float variance, brightness, ConvBrightness, 3);
+                    //Debug.Log(counter + "Variance: " + variance);
+                    //Debug.Log(counter + "CircleBrightness: " + value);
+                    //Debug.Log(counter + "CircleRadius: " + area.MaxRadius);
+
+                    if (variance < 30)
+                    {
+                        CircleAreas.Add(area);
+                    }
+
+                    //if (maxCircleBrightness == 10000f) 
+                    //{
+                    //    maxCircleBrightness = value;
+                    //    maxBrightArea = area;
+                    //}
+                    //else if (maxCircleBrightness < value || (maxCircleBrightness == value && area.Pixels.Count > maxBrightArea.Pixels.Count)) 
+                    //{
+                    //    maxCircleBrightness = value;
+                    //    maxBrightArea = area;
+                    //}
+                }
+                //Debug.Log("CricleBrightness: " + maxCircleBrightness);
+
+                //Debug.Log(counter + "CircleAreas: " + CircleAreas.Count);
+                //counter++;
+                if (CircleAreas.Count == 0)
+                    return null;
+                if (CircleAreas.Count == 1)
+                    return new List<Vector2> { CircleAreas[0].Center };
+
+                CircleAreas.Sort((a, b) => b.MaxRadius.CompareTo(a.MaxRadius));
+                return new List<Vector2> { CircleAreas[0].Center, CircleAreas[1].Center };
+            }
+
+            return null;
+        }
+
+        InfraredSpot[] MatchInfraredRay(List<PixelSpotArea> spotArea)
+        {
+            var matchedArea = new Dictionary<InfraredMatch, PixelSpotArea>() { { InfraredMatch.Match0, null }, { InfraredMatch.Match1, null } };
+            var v0 = InfraredSpots[0].Verify(spotArea, matchedArea);
+            var v1 = InfraredSpots[1].Verify(spotArea, matchedArea);
+
+            if (!Infrared12Overlap)
+            {
+                if (!v0 && !v1)
+                {
+                    //Application.targetFrameRate = 1;
+                    //Debug.Log($"{Time.time}全失败 spotArea {spotArea.Count}");
+                    if (spotArea.Count == 0)
+                    {
+                        //InfraredSpots[0].UpdateByPredict();
+                        //InfraredSpots[1].UpdateByPredict();
+                    }
+                    else if (spotArea.Count == 1)
+                    {
+                        if (InfraredSpots[0].Predict != null && InfraredSpots[1].Predict == null)
+                        {
+                            matchedArea[InfraredMatch.Match0] = spotArea[0];
+                            //InfraredSpots[0].Update(spotArea[0]);
+                            //InfraredSpots[1].UpdateByPredict();
+                        }
+                        else if (InfraredSpots[1].Predict != null && InfraredSpots[0].Predict == null)
+                        {
+                            matchedArea[InfraredMatch.Match1] = spotArea[0];
+                        }
+                        else
+                        {
+                            if (spotArea[0].Radius > infraredSpotSettings.RadiusThreshold)
+                            {
+                                matchedArea[InfraredMatch.Match0] = spotArea[0];
+                            }
+                            else
+                            {
+                                matchedArea[InfraredMatch.Match1] = spotArea[0];
+                            }
+                        }
+                    }
+                    else
+                    {
+                        spotArea.Sort((a, b) => b.Radius.CompareTo(a.Radius));                    // 排序亮区
+                        matchedArea[InfraredMatch.Match0] = spotArea[0];
+                        matchedArea[InfraredMatch.Match1] = spotArea[1];
+                    }
+                }
+                else
+                {
+                    PixelSpotArea select = null;
+                    PixelSpotArea selectOther = null;
+                    InfraredMatch oneFailed = InfraredMatch.Nomatch;
+                    if (!v0)
+                    {
+                        select = matchedArea[InfraredMatch.Match1];
+                        //InfraredSpots[1].Update(select);
+                        oneFailed = InfraredMatch.Match0;
+                    }
+                    else if (!v1)
+                    {
+                        select = matchedArea[InfraredMatch.Match0];
+                        //InfraredSpots[0].Update(select);
+                        oneFailed = InfraredMatch.Match1;
+                    }
+
+                    if (oneFailed != InfraredMatch.Nomatch)
+                    {
+                        //Debug.LogWarning($"{Time.time}成功1个 {oneFailed}");
+                        spotArea.Sort((a, b) => b.Radius.CompareTo(a.Radius));                        // 排序亮区
+                        foreach (var i in spotArea)
+                        {
+                            if (i != select)
+                            {
+                                selectOther = i;
+                                break;
+                            }
+                        }
+                        matchedArea[oneFailed] = selectOther;
+                        //if (selectOther == null)
+                        //{
+                        //    GetSpot(oneFailed).UpdateByPredict();
+                        //}
+                        //else
+                        //{
+                        //    GetSpot(oneFailed).Update(selectOther);
+                        //}
+                    }
+                    else
+                    {
+                        //Debug.LogWarning($"{Time.time}成功2个");
+                        if (matchedArea[InfraredMatch.Match0] == matchedArea[InfraredMatch.Match1])
+                        {
+                            // 重叠
+                            Infrared12Overlap = true;
+                            //if (spotArea.Count == 1)
+                            //{
+                            //    Infrared12Overlap = true;
+
+                            //    InfraredSpots[0].Update(spotArea[0]);
+                            //    InfraredSpots[1].UpdateByPredict();
+                            //    return InfraredSpots;
+                            //}
+                            //else
+                            //{
+                            //    Infrared12Overlap = false;
+                            //    spotArea.Sort((a, b) => b.Radius.CompareTo(a.Radius));                    // 排序亮区
+                            //    InfraredSpots[0].Update(spotArea[0]);
+                            //    InfraredSpots[1].Update(spotArea[1]);
+                            //}
+                        }
+                        else //if (matchedArea[InfraredMatch.Match1] != matchedArea[InfraredMatch.Match2])
+                        {
+                            //Infrared12Overlap = false;
+                            //InfraredSpots[0].Update(matchedArea[InfraredMatch.Match0]);
+                            //InfraredSpots[1].Update(matchedArea[InfraredMatch.Match1]);
+
+                            // 每隔20帧更新阈值
+                            if (++cheakCounter >= CheakFrame)
+                            {
+                                //Debug.Log($"{Time.time}更新阈值2个");
+                                var middle = (matchedArea[InfraredMatch.Match0].Radius + matchedArea[InfraredMatch.Match1].Radius) / 2;
+                                infraredSpotSettings.UpdateThreshold(middle);
+                                cheakCounter = 0;
+                                if (matchedArea[InfraredMatch.Match0].Radius < middle)
+                                {
+                                    //Debug.Log($"{Time.time}大小异常");
+                                    InfraredSpots[0].Reset();       // 防止异常
+                                    InfraredSpots[1].Reset();
+                                }
+                            }
+                        }
+                    }
+
+                }
+            }
+
+            if (Infrared12Overlap)
+            {
+                if (v0)
+                {
+                    var overlapAera = matchedArea[InfraredMatch.Match0];
+                    (PixelSpotArea, float) split = (null, float.MaxValue);
+                    foreach (var i in spotArea)
+                    {
+                        if (i != overlapAera)
+                        {
+                            var distance = (i.Center - overlapAera.Center).magnitude;
+                            if (distance < overlapAera.Radius * 2 && distance < split.Item2)
+                            {
+                                split = (i, distance);
+                            }
+                        }
+                    }
+                    if (split.Item1 != null)
+                    {
+                        //InfraredSpots[0].Update(overlapAera);
+                        //InfraredSpots[1].Update(split.Item1);
+                        matchedArea[InfraredMatch.Match1] = split.Item1;
+                        InfraredSpots[1].Disappear = false;
+                        Infrared12Overlap = false;
+                    }
+                    else
+                    {
+                        if ((InfraredSpots[1].Predict.Value - overlapAera.Center).magnitude > overlapAera.Radius / 2)
+                            InfraredSpots[1].Disappear = true;
+
+                        //InfraredSpots[0].Update(overlapAera);
+                        if (InfraredSpots[1].Predict == null || InfraredSpots[1].Disappear)
+                        {
+                            //InfraredSpots[1].Update(overlapAera);
+                            matchedArea[InfraredMatch.Match1] = overlapAera;
+                            InfraredSpots[1].Predict = null;
+                        }
+                        else
+                        {
+                            matchedArea[InfraredMatch.Match1] = null;
+                            //InfraredSpots[1].UpdateByPredict();
+                        }
+
+                        //if (++cheakCounter >= 20 * cheakFrame)
+                        //{
+                        //    cheakCounter = 0;
+                        //    InfraredSpots[1].Reset();
+                        //    Infrared12Overlap = false;
+                        //}
+                    }
+                }
+                else
+                {
+                    //InfraredSpots[0].UpdateByPredict();
+                    //InfraredSpots[1].UpdateByPredict();
+                    matchedArea[InfraredMatch.Match1] = null;
+                }
+            }
+
+            foreach (var i in matchedArea)
+                GetSpot(i.Key).Update(i.Value);
+
+            return InfraredSpots;
+        }
+
+        // 亮度图是64位整形,返回卷积后的均值是float
+        float ConvBrightness(int[] pixels, (int x, int y) point, int kernel_size = 3)
+        {
+            var sum = 0f;
+            for (int i = point.x - kernel_size / 2; i <= point.x + kernel_size / 2; i++)
+            {
+                for (int j = point.y - kernel_size / 2; j <= point.y + kernel_size / 2; j++)
+                {
+                    var index = mCameraInfo.CoordToIndex(i, j);
+                    if (index > 0 && index < pixels.Length)       // 超出边缘不计算
+                        sum += pixels[index];
+                }
+            }
+            return sum / (kernel_size * kernel_size);
+        }
+
+        //(int max, int second) MaxAreaIndex(Color[] pixels, List<PixelArea> list)
+        //{
+        //    var maxValue = float.MinValue;
+        //    var secondValue = float.MinValue;
+        //    var max = 0;
+        //    var second = 0;
+        //    foreach (var i in list.Index())
+        //    {
+        //        var value = list[i].TotalBrightness(pixels, camera.Vector2ToIndex, samplingScale * 2);
+        //        if (value > maxValue)
+        //        {
+        //            maxValue = value;
+        //            max = i;
+        //        }
+        //        else if (maxValue > secondValue)
+        //        {
+        //            secondValue = value;
+        //            second = i;
+        //        }
+        //    }
+        //    return (max, second);
+        //}
+
+        //float CricleVariance(int[] pixels, PixelArea area, int kernel_size = 3)
+        //{
+        //    var hash = new HashSet<(int, int)>();
+        //    foreach (var (cos,sin) in angleMathList)
+        //    {
+        //        var x = (int)Math.Round(area.Center.x + (area.MaxRadius + PixelArea.gridLength * 4) * cos);
+        //        var y = (int)Math.Round(area.Center.y + (area.MaxRadius + PixelArea.gridLength * 4) * sin);
+        //        hash.Add((x, y));
+        //    }
+        //    var avg = 0f;
+        //    foreach (var p in hash)
+        //    {
+        //        var value = ConvBrightness(pixels, p, kernel_size);
+        //        avg += value;
+        //    }
+        //    return avg / hash.Count;
+        //}
+
+        //class PixelArea
+        //{
+        //    public static int gridLength;
+        //    public static (int x, int y) gridSize;
+        //    public static (int x, int y) GetGrid(Vector2 v)
+        //    {
+        //        var m = (int)(v.x / gridLength);
+        //        var n = (int)(v.y / gridLength);
+        //        return (m, n);
+        //    }
+
+        //    public Vector2 Center;
+        //    public List<Vector2> Pixels;
+
+        //    public PixelArea(Vector2 location)
+        //    {
+        //        this.Center = location;
+        //        this.Pixels = new List<Vector2> { location };
+        //    }
+        //}
+    }
+}
+

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredLocate.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d121e97ab2cdd2140a87bec76e3761e9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8a0aeb2277775b54e9cd726b929a80e1
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 156 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpot.cs

@@ -0,0 +1,156 @@
+using System.Collections.Generic;
+using UnityEngine;
+using ZIM.Unity;
+using Color = UnityEngine.Color;
+
+namespace ZIM
+{
+    public class InfraredSpot
+    {
+        // 达到该数量才完成初始化
+        //static int InitCount = 5;
+        static int MaxVerifyFailLimit = 20;
+        public static float MinVerifyLength = 240;
+
+        // 返回null代表没有点,范围在[0, 1]内
+        public Vector2? ScreenUV
+        {
+            get
+            {
+                if (ScreenLocation.HasValue)
+                {
+                    return screenMap.UVNormalize(ScreenLocation.Value);
+                }
+                else
+                {
+                    return null;
+                }
+            }
+        }
+        // 范围在摄像机的Size内
+        public Vector2? CameraLocation { 
+            get
+            {
+                if (ScreenLocation.HasValue)
+                {
+                    return screenMap.TransformToCamera(ScreenLocation.Value);
+                }
+                else
+                    return null;
+            }
+        }
+        public Vector2? Predict { get; set; }        // 为null时代表未初始化
+        public InfraredMatch Match { get; private set; }
+
+        public bool Disappear;
+
+        //PixelSpotArea verifyArea;
+        int verifyFailLimit;
+
+        List<PixelSpotArea> spots;
+        SimpleLocationEstimation estimation;
+        Vector2? ScreenLocation;
+        ScreenMap screenMap;
+
+        public InfraredSpot(ScreenMap screenMap, InfraredMatch match)
+        {
+            this.screenMap = screenMap;
+            MinVerifyLength = screenMap.UVSize.y / 5;
+            Match = match;
+            spots = new List<PixelSpotArea>();
+            Reset();
+        }
+
+        public void Reset() {
+            spots.Clear();
+            estimation = new SimpleLocationEstimation(0.5f);
+            ScreenLocation = null;
+            Predict = null;
+            Disappear = false;
+            //verifyArea = null;
+            verifyFailLimit = MaxVerifyFailLimit;
+        }
+
+        public bool Verify(List<PixelSpotArea> areas, Dictionary<InfraredMatch, PixelSpotArea> matchedArea)
+        {
+            if (Predict == null)    // 未初始化
+                return false;      
+
+            PixelSpotArea select = null;
+            var minLength = float.MaxValue;
+            var predict = Predict.Value;
+            foreach (var i in areas)
+            {
+                var len = (i.Center - predict).magnitude;
+                if ( len < MinVerifyLength) 
+                {
+                    if (len < minLength) 
+                    {
+                        select = i;
+                        minLength = len;
+                    }
+                }
+            }
+
+            if (select == null)
+            {
+                //Debug.Log(verifyFailLimit);
+                verifyFailLimit--;
+                if (verifyFailLimit == 0) 
+                    Reset();
+                return false;
+            }
+
+            //verifyArea = select;
+            matchedArea[Match] = select;
+            return true;
+        }
+
+        //public void UpdateByVerifyArea()
+        //{
+        //    Update(verifyArea);
+        //}
+
+        // 为null时采用预测点
+        public void Update(PixelSpotArea area)
+        {
+            if (area == null)
+            {
+                //throw new System.Exception("[InfraredSpot] Update Wrong");
+                UpdateByPredict();
+                return;
+            }
+
+            var predict = estimation.Update(area.Center);
+            //ScreenLocation = area.Center;
+            ScreenLocation = area.Center * 0.8f + predict * 0.2f;
+            spots.Add(area);
+            if (spots.Count > 15) 
+            {
+                Predict = predict;
+                spots.RemoveAt(0);
+            }
+        }
+
+        void UpdateByPredict()
+        {
+            if (spots.Count != 0)
+            {
+                if (Predict == null)         // 还未初始化,直接Reset
+                    Reset();
+                else
+                {
+                    // 采用预测点,但超出屏幕则Reset
+                    if (screenMap.UVInScreen(Predict.Value))
+                    {
+                        ScreenLocation = Predict;
+                        var newP = estimation.Update(Predict.Value);
+                        Predict = newP;
+                    }
+                    else
+                        Reset();
+                }
+            }
+        }
+    }
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpot.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5383e127ec9892b41aa44e6326b35da9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 15 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpotSettings.asset

@@ -0,0 +1,15 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 0}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: a02457a34811484449c5aea53ab9df1b, type: 3}
+  m_Name: InfraredSpotSettings
+  m_EditorClassIdentifier: Assembly-CSharp::InfraredSpotThreshold
+  RadiusThreshold: 60

+ 8 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpotSettings.asset.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ca2f3b215f8d9d64caed905436a89b86
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 11400000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 31 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpotSettings.cs

@@ -0,0 +1,31 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using Unity.VisualScripting;
+using UnityEngine;
+
+[CreateAssetMenu(fileName = "InfraredSpotSettings", menuName = "ScriptableObjects/InfraredSpotSettings", order = 1)]
+public class InfraredSpotSettings : ScriptableObject
+{
+    public float RadiusThreshold = 100f;      // 初始阈值参考价值不大,每个环境都不一样?
+
+    List<float> data;
+
+    public InfraredSpotSettings()
+    {
+        data = new List<float>(50);
+        data.AddRange(Enumerable.Repeat(RadiusThreshold, 3));
+    }
+    public void UpdateThreshold(float data)
+    {
+        var sum = RadiusThreshold * this.data.Count() + data;
+        if (this.data.Count >= 100)
+        {
+            sum -= this.data[0];
+            this.data.RemoveAt(0);
+        }
+        this.data.Add(data);
+
+        RadiusThreshold = sum / this.data.Count();
+    }
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/InfraredSpotSettings.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a02457a34811484449c5aea53ab9df1b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 131 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelArea.cs

@@ -0,0 +1,131 @@
+using o0;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Unity.VisualScripting;
+using UnityEngine;
+using Color = UnityEngine.Color;
+
+namespace ZIM
+{
+    internal class PixelArea
+    {
+        public static int gridLength = 16;
+        //public static (int x, int y) gridSize;
+        public static (int x, int y) GetGrid(Vector2 v)
+        {
+            var m = (int)(v.x / gridLength);
+            var n = (int)(v.y / gridLength);
+            return (m, n);
+        }
+        public static List<(double cos, double sin)> AngleMathList {
+            get
+            {
+                if (angleMathList != null)
+                    return angleMathList;
+                // 三角函数值记录在list中
+                double step = angleStep * 0.017453292519943295;
+                angleMathList = new List<(double cos, double sin)>();
+                for (double i = 0; i < 6.2831853; i += step)
+                {
+                    var cos = Math.Cos(i);
+                    var sin = Math.Sin(i);
+                    angleMathList.Add((cos, sin));
+                }
+                return angleMathList;
+            }
+
+        }
+
+        static float angleStep = 11.25f;
+        static List<(double cos, double sin)> angleMathList;
+
+
+        public Vector2 Center;
+        public float MaxRadius;
+        public HashSet<Vector2> Pixels;
+
+        HashSet<(int, int)> grids;
+
+        public PixelArea(Vector2 location)
+        {
+            Center = location;
+            Pixels = new HashSet<Vector2> { location };
+            MaxRadius = 0;
+            grids = new HashSet<(int, int)>();
+            Add(location);
+        }
+
+        public PixelArea(IList<PixelArea> areas)
+        {
+            Center = Vector2.zero;
+            Pixels = new HashSet<Vector2>();
+            MaxRadius = 0;
+            grids = new HashSet<(int, int)>();
+            foreach (var a in areas)
+            {
+                Pixels.AddRange(a.Pixels);
+                grids.AddRange(a.grids);
+            }
+            foreach (var p in Pixels)
+            {
+                Center += p;
+            }
+            Center /= Pixels.Count;
+            foreach (var p in Pixels)
+            {
+                var radius = (p - Center).magnitude;
+                if (radius > MaxRadius)
+                    MaxRadius = radius;
+            }
+        }
+
+        public bool Include((int, int) grid) => grids.Contains(grid);
+
+        public void Add(Vector2 point) => Add(point, GetGrid(point));
+
+        public void Add(Vector2 point, (int x, int y) grid)
+        {
+            Center += (point - Center) / Pixels.Count;
+            var radius = (point - Center).magnitude;
+            if (radius > MaxRadius)
+                MaxRadius = radius;
+
+            Pixels.Add(point);
+            grids.AddRange(new (int, int)[]
+            {
+                    (grid.x + -1, grid.y +  0) , (grid.x + 1 , grid.y + 0),
+                    (grid.x + 1,  grid.y + -1) , (grid.x + -1, grid.y + 1),
+                    (grid.x + 0,  grid.y + -1) , (grid.x + 0 , grid.y + 1),
+                    (grid.x + -1, grid.y + -1) , (grid.x + 1 , grid.y + 1),
+                    grid
+            });
+        }
+
+        public float TotalBrightness(Color[] pixels,Func<int,int,int> Vector2ToIndex, int outer_size = 3)
+        {
+            (int x, int y) rectMin = ((int)(Center.x - MaxRadius - outer_size), (int)(Center.y - MaxRadius - outer_size));
+            (int x, int y) rectMax = ((int)(Center.x + MaxRadius + outer_size), (int)(Center.y + MaxRadius + outer_size));
+
+            var total = 0f;
+            Parallel.For(rectMin.x, rectMax.x, (i) =>
+            {
+                var t = 0;
+                for (int j = rectMin.y; j < rectMax.y; j++)
+                {
+                    var index = Vector2ToIndex(i, j);
+                    var b = pixels[index].Brightness(64);
+                    t += b;
+                }
+                lock (InfraredLocate.locker)
+                {
+                    total += t;
+                }
+            });
+            //total /= (rectMax.y - rectMin.y) * (rectMax.x - rectMin.x);
+
+            return total;
+        }
+    }
+
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelArea.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 538d0287447cd0741b9a4a744cbf3008
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 99 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelCircleArea.cs

@@ -0,0 +1,99 @@
+using o0;
+using System;
+using System.Collections.Generic;
+using Unity.VisualScripting;
+using UnityEngine;
+
+namespace ZIM
+{
+    internal class PixelCircleArea
+    {
+        public Vector2 Center;
+        public float MaxRadius;
+        public HashSet<Vector2> Pixels;
+
+        HashSet<(int, int)> grids;
+
+        public PixelCircleArea(Vector2 location)
+        {
+            Center = location;
+            Pixels = new HashSet<Vector2> { location };
+            MaxRadius = 0;
+            grids = new HashSet<(int, int)>();
+            Add(location);
+        }
+
+        public PixelCircleArea(IList<PixelCircleArea> areas)
+        {
+            Center = Vector2.zero;
+            Pixels = new HashSet<Vector2>();
+            MaxRadius = 0;
+            grids = new HashSet<(int, int)>();
+            foreach (var a in areas)
+            {
+                Pixels.AddRange(a.Pixels);
+                grids.AddRange(a.grids);
+            }
+            foreach (var p in Pixels)
+            {
+                Center += p;
+            }
+            Center /= Pixels.Count;
+            foreach (var p in Pixels)
+            {
+                var radius = (p - Center).magnitude;
+                if (radius > MaxRadius)
+                    MaxRadius = radius;
+            }
+        }
+
+        public bool Include((int, int) grid) => grids.Contains(grid);
+
+        public void Add(Vector2 point) => Add(point, PixelArea.GetGrid(point));
+
+        public void Add(Vector2 point, (int x, int y) grid)
+        {
+            Center += (point - Center) / Pixels.Count;
+            var radius = (point - Center).magnitude;
+            if (radius > MaxRadius)
+                MaxRadius = radius;
+
+            Pixels.Add(point);
+            grids.AddRange(new (int, int)[]
+            {
+                    (grid.x + -1, grid.y +  0) , (grid.x + 1 , grid.y + 0),
+                    (grid.x + 1,  grid.y + -1) , (grid.x + -1, grid.y + 1),
+                    (grid.x + 0,  grid.y + -1) , (grid.x + 0 , grid.y + 1),
+                    (grid.x + -1, grid.y + -1) , (grid.x + 1 , grid.y + 1),
+                    grid
+            });
+        }
+
+        public float CircleBrightness(out float variance, int[] pixels, Func<int[], (int, int), int, float> GetBrightness, int kernel_size = 3)
+        {
+            var hash = new HashSet<(int, int)>();
+            foreach (var (cos, sin) in PixelArea.AngleMathList)
+            {
+                var x = (int)Math.Round(Center.x + (MaxRadius + 1) * cos);        // +1防止区域太小
+                var y = (int)Math.Round(Center.y + (MaxRadius + 1) * sin);
+                hash.Add((x, y));
+            }
+            var sum = 0f;
+            var sum2 = 0f;
+            foreach (var p in hash)
+            {
+                var value = GetBrightness(pixels, p, kernel_size);
+                sum += value;
+                sum2 += value * value;
+            }
+            var avg = sum / hash.Count;
+            variance = sum2 / hash.Count - avg * avg;
+            //Debug.Log(hash.Count + "   --  bright: " + avg);
+
+            return avg;
+        }
+
+
+    }
+
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelCircleArea.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 98eb535bebc4df44bb2b62af2c0482ae
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 214 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelSpotArea.cs

@@ -0,0 +1,214 @@
+using o0;
+using o0.Num;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using UnityEngine;
+using Color = UnityEngine.Color;
+
+namespace ZIM
+{
+    public class PixelSpotArea
+    {
+        public static int gridLength0 = 6;      // 亮区
+        public static int gridLength1 = 20;     // 边缘泛光
+
+        public static (int x, int y) GetGrid0(Vector2 v)
+        {
+            var m = (int)(v.x / gridLength0);
+            var n = (int)(v.y / gridLength0);
+            return (m, n);
+        }
+
+        public static (int x, int y) GetGrid1(Vector2 v)
+        {
+            var m = (int)(v.x / gridLength1);
+            var n = (int)(v.y / gridLength1);
+            return (m, n);
+        }
+
+        // 亮点聚类到区域
+        public static List<PixelSpotArea> Cluster(List<Vector2> spotPoint, List<Vector2> brightPoint, Func<Vector2, bool> PointFilter = null)
+        {
+            var spotArea = new List<PixelSpotArea>();
+            for (int i = 0; i < spotPoint.Count; i++)
+            {
+                var p = spotPoint[i];
+                if (PointFilter != null && !PointFilter(p))        // 筛选是否在屏幕内
+                    continue;
+
+                var grid = PixelSpotArea.GetGrid0(p);
+                var join = new SortedList<int, PixelSpotArea>();
+                for (int j = 0; j < spotArea.Count; j++)
+                {
+                    var area = spotArea[j];
+                    if (area.Include0(grid))
+                        join.Add(j, area);
+                }
+                if (join.Count == 0)
+                    spotArea.Add(new PixelSpotArea(p, grid, PixelSpotArea.GetGrid1(p)));
+                else if (join.Count == 1)
+                    join.First().Value.Join(p, grid, PixelSpotArea.GetGrid1(p));
+                else
+                {
+                    var combine = new PixelSpotArea(join.Values);
+                    combine.Join(p, grid, PixelSpotArea.GetGrid1(p));
+                    spotArea.Add(combine);
+                    for (int j = join.Count - 1; j >= 0; j--)
+                        spotArea.RemoveAt(join.ElementAt(j).Key);
+                }
+            }
+            return spotArea;
+        }
+
+        Vector2 center = default;       // 该项目里center不可能等于0,0
+        public Vector2 Center
+        {
+            get
+            {
+                if (center != default)
+                    return center;
+
+                foreach (var p in Pixels0)
+                {
+                    center += p;
+                }
+                return center /= Pixels0.Count;
+            }
+        }
+        float radius = 0;
+        public float Radius
+        {
+            set
+            {
+                radius = value;
+            }
+            get
+            {
+                if (radius != 0)
+                    return radius;
+
+                //var radiusDic = new Dictionary<int, float>() { { 0, 0 }, { 45, 0 }, { 90, 0 }, { 135, 0 }, { 180, 0 }, { 225, 0 }, { 270, 0 }, { 315, 0 } };
+                var radiusDic = new float[8];
+                foreach (var p in Pixels0)
+                {
+                    var dir = p - Center;
+                    var radius = dir.magnitude;
+                    var degreeI = radius < 0.00001f ? 0 : (int)(dir.DegreeToXAxis() / 45);
+
+                    if (radius > radiusDic[degreeI])
+                        radiusDic[degreeI] = radius;
+                }
+
+                foreach (var p in Pixels1)
+                {
+                    var dir = p - Center;
+                    var radius = dir.magnitude;
+                    var degreeI = radius < 0.00001f ? 0 : (int)(dir.DegreeToXAxis() / 45);
+
+                    if (radius > radiusDic[degreeI])
+                        radiusDic[degreeI] = radius;
+                }
+                return radius = radiusDic.Mean();
+            }
+        }
+
+        public List<Vector2> Pixels0;
+        public List<Vector2> Pixels1;
+
+        HashSet<(int, int)> grids0;
+        HashSet<(int, int)> grids1;
+
+        public PixelSpotArea(Vector2 location, (int, int) grid0, (int, int) grid1)
+        {
+            Pixels0 = new List<Vector2>(1000);       // 预估的初始容量
+            Pixels1 = new List<Vector2>(5000);
+            this.grids0 = new HashSet<(int, int)>();        // hashset如果设置了太大的容量会降低效率
+            this.grids1 = new HashSet<(int, int)>();
+            Join(location, grid0, grid1);
+        }
+
+        public PixelSpotArea(IList<PixelSpotArea> areas)
+        {
+            Pixels0 = new List<Vector2>(1000);
+            Pixels1 = new List<Vector2>(5000);
+            grids0 = new HashSet<(int, int)>();
+            grids1 = new HashSet<(int, int)>();
+            foreach (var a in areas)
+            {
+                Pixels0.AddRange(a.Pixels0);
+                grids0.AddRange(a.grids0);
+                grids1.AddRange(a.grids1);
+                //Center += a.Center * a.SpotPointCount;
+                //SpotPointCount += a.SpotPointCount;
+            }
+            //Center /= SpotPointCount;
+        }
+
+        public bool Include0((int, int) grid) => grids0.Contains(grid);
+        public bool Include1((int, int) grid) => grids1.Contains(grid);
+
+        public void Join(Vector2 point) => Join(point, GetGrid0(point), GetGrid1(point));
+        public void Join(Vector2 point, (int x, int y) grid0, (int x, int y) grid1)
+        {
+            Pixels0.Add(point);
+            //SpotPointCount++;
+            //Center += (point - Center) / SpotPointCount;
+            grids0.AddRange(new (int, int)[]
+            {
+                    (grid0.x + -1, grid0.y +  0) , (grid0.x + 1 , grid0.y + 0),
+                    (grid0.x + 1,  grid0.y + -1) , (grid0.x + -1, grid0.y + 1),
+                    (grid0.x + 0,  grid0.y + -1) , (grid0.x + 0 , grid0.y + 1),
+                    (grid0.x + -1, grid0.y + -1) , (grid0.x + 1 , grid0.y + 1),
+                    grid0
+            });
+            grids1.AddRange(new (int, int)[]
+            {
+                    (grid1.x + -1, grid1.y +  0) , (grid1.x + 1 , grid1.y + 0),
+                    (grid1.x + 1,  grid1.y + -1) , (grid1.x + -1, grid1.y + 1),
+                    (grid1.x + 0,  grid1.y + -1) , (grid1.x + 0 , grid1.y + 1),
+                    (grid1.x + -1, grid1.y + -1) , (grid1.x + 1 , grid1.y + 1),
+                    grid1
+            });
+        }
+
+        // 不再join之后,才可以用add添加周围泛光
+        public void Add(Vector2 point)
+        {
+            //var radius = (point - Center).LengthManhattan();
+            //if (radius > MaxRadius)
+            //    MaxRadius = radius;
+            Pixels1.Add(point);
+            //var radius = (point - Center).LengthManhattan();
+            //if (radius > MaxRadius)
+            //    MaxRadius = radius;
+        }
+
+        public float TotalBrightness(Color[] pixels, Func<int, int, int> Vector2ToIndex, int outer_size = 3)
+        {
+            (int x, int y) rectMin = ((int)(Center.x - Radius - outer_size), (int)(Center.y - Radius - outer_size));
+            (int x, int y) rectMax = ((int)(Center.x + Radius + outer_size), (int)(Center.y + Radius + outer_size));
+
+            var total = 0f;
+            Parallel.For(rectMin.x, rectMax.x, (i) =>
+            {
+                var t = 0;
+                for (int j = rectMin.y; j < rectMax.y; j++)
+                {
+                    var index = Vector2ToIndex(i, j);
+                    var b = pixels[index].Brightness(64);
+                    t += b;
+                }
+                lock (InfraredLocate.locker)
+                {
+                    total += t;
+                }
+            });
+            //total /= (rectMax.y - rectMin.y) * (rectMax.x - rectMin.x);
+
+            return total;
+        }
+    }
+
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/InfraredSpot/PixelSpotArea.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 14094e24894f86145bf54897536727c8
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 275 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/PerspectiveTransform.cs

@@ -0,0 +1,275 @@
+using System;
+using System.Diagnostics;
+using o0.Geometry2D.Float;
+
+// 其实这个类内部是用Double计算的
+namespace ZIM
+{
+    // 来源 https://web.archive.org/web/20150222120106/xenia.media.mit.edu/~cwren/interpolator/
+    public class ZIMPerspectiveTransform
+    {
+        // 变换矩阵
+        double[,] H;
+        double[,] InverseH;
+
+        public ZIMPerspectiveTransform(OrdinalQuadrilateral src, OrdinalQuadrilateral dst)
+        {
+            // 该算法点序为 左下角开始 顺时针
+            double[] X = new double[4] { src.A.x, src.C.x, src.D.x, src.B.x };
+            double[] Y = new double[4] { src.A.y, src.C.y, src.D.y, src.B.y };
+
+            double[] Xp = new double[4] { dst.A.x, dst.C.x, dst.D.x, dst.B.x };
+            double[] Yp = new double[4] { dst.A.y, dst.C.y, dst.D.y, dst.B.y };
+
+            TransformEstimate(X, Y, Xp, Yp);
+
+            //UnityEngine.Debug.Log(H.ToJson(true));
+            //UnityEngine.Debug.Log(H[0, 0]);
+            //UnityEngine.Debug.Log(H[0, 1]);
+            //UnityEngine.Debug.Log(H[0, 2]);
+        }
+
+        //public Vector Transform(Vector v)
+        //{
+        //    var result = Transform(v.x, v.y);
+        //    return new Vector((float)result.x, (float)result.y);
+        //}
+
+        public (int x, int y) TransformRound(int x, int y)
+        {
+            var result = Transform((double)x, (double)y);
+            return ((int)Math.Round(result.x), (int)Math.Round(result.y));
+        }
+
+        public (float x, float y) Transform(float x, float y)
+        {
+            var result = Transform((double)x, (double)y);
+            return ((float)result.x, (float)result.y);
+        }
+
+        public (double x, double y) Transform(double x, double y)
+        {
+            double t1 = H[0, 0] * x + H[0, 1] * y + H[0, 2];
+            double t2 = H[1, 0] * x + H[1, 1] * y + H[1, 2];
+            double t3 = H[2, 0] * x + H[2, 1] * y + H[2, 2];
+            return (t1 / t3, t2 / t3);
+        }
+
+        public (float x, float y) TransformInverse(float x, float y)
+        {
+            var result = TransformInverse((double)x, (double)y);
+            return ((float)result.x, (float)result.y);
+        }
+
+        public (double x, double y) TransformInverse(double x, double y)
+        {
+            double t1 = InverseH[0, 0] * x + InverseH[0, 1] * y + InverseH[0, 2];
+            double t2 = InverseH[1, 0] * x + InverseH[1, 1] * y + InverseH[1, 2];
+            double t3 = InverseH[2, 0] * x + InverseH[2, 1] * y + InverseH[2, 2];
+            return (t1 / t3, t2 / t3);
+        }
+
+        // Calculate matrix transform
+        void TransformEstimate(double[] X, double[] Y, double[] Xp, double[] Yp)
+        {
+            //double[] Xp = { 0, 0, 1280, 1280 };
+            //double[] Yp = { 0, 720, 720, 0 };
+            double[,] B = new double[8, 8];
+            double[,] D = new double[8, 1];
+
+            for (int i = 0; i < 4; i++)
+            {
+                B[i, 0] = X[i];
+                B[i, 1] = Y[i];
+                B[i, 2] = 1;
+                B[i, 6] = -X[i] * Xp[i];
+                B[i, 7] = -Y[i] * Xp[i];
+
+                B[i + 4, 3] = X[i];
+                B[i + 4, 4] = Y[i];
+                B[i + 4, 5] = 1;
+                B[i + 4, 6] = -X[i] * Yp[i];
+                B[i + 4, 7] = -Y[i] * Yp[i];
+            }
+
+            for (int i = 0; i < 4; i++)
+            {
+                D[i, 0] = Xp[i];
+                D[i + 4, 0] = Yp[i];
+            }
+
+            double[,] BTranspose = TransposeMatrix(B);
+            double[,] l = MatrixMultiply(MatrixMultiply(MatrixInverse(MatrixMultiply(BTranspose, B)), BTranspose), D);      // l 是8行1列的矩阵
+
+            H = new double[3, 3] { { l[0, 0], l[1, 0], l[2, 0] }, { l[3, 0], l[4, 0], l[5, 0] }, { l[6, 0], l[7, 0], 1 } };
+            InverseH = MatrixInverse(H);
+
+            // 测试代码
+            //var x1 = X[2];
+            //var y1 = Y[2];
+            //var x2 = X[0];
+            //var y2 = Y[0];
+
+            //// Plot the points and their transformed coordinates
+            //UnityEngine.Debug.Log("Plotting the points and their transformed coordinates...");
+            //for (double u = 0; u <= 1; u += 0.1)
+            //{
+            //    double x = u * x1 + (1 - u) * x2;
+            //    double y = u * y1 + (1 - u) * y2;
+            //    UnityEngine.Debug.Log($"Point ({x}, {y})");
+
+            //    double t1 = H[0, 0] * x + H[0, 1] * y + H[0, 2];
+            //    double t2 = H[1, 0] * x + H[1, 1] * y + H[1, 2];
+            //    double t3 = H[2, 0] * x + H[2, 1] * y + H[2, 2];
+            //    double tX = t1 / t3;
+            //    double tY = t2 / t3;
+            //    UnityEngine.Debug.Log($"Transformed point ({tX}, {tY})");
+            //}
+        }
+
+        static double[,] TransposeMatrix(double[,] matrix)
+        {
+            int rows = matrix.GetLength(0);
+            int cols = matrix.GetLength(1);
+            double[,] result = new double[cols, rows];
+
+            for (int i = 0; i < rows; i++)
+            {
+                for (int j = 0; j < cols; j++)
+                {
+                    result[j, i] = matrix[i, j];
+                }
+            }
+
+            return result;
+        }
+
+        static double[,] ReshapeMatrix(double[,] matrix, int rows, int cols)
+        {
+            int originalRows = matrix.GetLength(0);
+            int originalCols = matrix.GetLength(1);
+
+            if (originalRows * originalCols != rows * cols)
+            {
+                throw new Exception("Invalid reshape dimensions");
+            }
+
+            double[,] result = new double[rows, cols];
+            int rowIndex = 0;
+            int colIndex = 0;
+
+            for (int i = 0; i < originalRows; i++)
+            {
+                for (int j = 0; j < originalCols; j++)
+                {
+                    result[rowIndex, colIndex] = matrix[i, j];
+                    colIndex++;
+
+                    if (colIndex == cols)
+                    {
+                        colIndex = 0;
+                        rowIndex++;
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        static double[,] ReshapeMatrix(double[] array, int rows, int cols)
+        {
+            double[,] result = new double[rows, cols];
+            int index = 0;
+
+            for (int j = 0; j < cols; j++)
+            {
+                for (int i = 0; i < rows; i++)
+                {
+                    result[i, j] = array[index];
+                    index++;
+                }
+            }
+
+            return result;
+        }
+
+        static double[,] MatrixMultiply(double[,] matrix1, double[,] matrix2)
+        {
+            int rows1 = matrix1.GetLength(0);
+            int cols1 = matrix1.GetLength(1);
+            int rows2 = matrix2.GetLength(0);
+            int cols2 = matrix2.GetLength(1);
+
+            if (cols1 != rows2)
+            {
+                throw new Exception("Invalid matrix dimensions");
+            }
+
+            double[,] result = new double[rows1, cols2];
+
+            for (int i = 0; i < rows1; i++)
+            {
+                for (int j = 0; j < cols2; j++)
+                {
+                    for (int k = 0; k < cols1; k++)
+                    {
+                        result[i, j] += matrix1[i, k] * matrix2[k, j];
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        static double[,] MatrixInverse(double[,] matrix)
+        {
+            int n = matrix.GetLength(0);
+            double[,] augmentedMatrix = new double[n, 2 * n];
+
+            for (int i = 0; i < n; i++)
+            {
+                for (int j = 0; j < n; j++)
+                {
+                    augmentedMatrix[i, j] = matrix[i, j];
+                }
+
+                augmentedMatrix[i, i + n] = 1;
+            }
+
+            for (int i = 0; i < n; i++)
+            {
+                double pivot = augmentedMatrix[i, i];
+
+                for (int j = 0; j < 2 * n; j++)
+                {
+                    augmentedMatrix[i, j] /= pivot;
+                }
+
+                for (int k = 0; k < n; k++)
+                {
+                    if (k != i)
+                    {
+                        double factor = augmentedMatrix[k, i];
+
+                        for (int j = 0; j < 2 * n; j++)
+                        {
+                            augmentedMatrix[k, j] -= factor * augmentedMatrix[i, j];
+                        }
+                    }
+                }
+            }
+
+            double[,] inverseMatrix = new double[n, n];
+
+            for (int i = 0; i < n; i++)
+            {
+                for (int j = 0; j < n; j++)
+                {
+                    inverseMatrix[i, j] = augmentedMatrix[i, j + n];
+                }
+            }
+
+            return inverseMatrix;
+        }
+    }
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/PerspectiveTransform.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 057edf2f645b28d49891378ad301325f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 690 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/ScreenIdentification.cs

@@ -0,0 +1,690 @@
+#define ENABLE_LOG
+
+using o0.Geometry2D.Float;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using UnityEngine;
+using ZIM;
+using ZIM.Unity;
+
+namespace o0.Project
+{
+    public partial class ScreenIdentification
+    {
+        private const string TAG = "ScreenIdentification#";
+
+        //static Rect[][] LocateAreaData = new Rect[][] {
+        //     new Rect[] { new Rect(0f, 0f, 0.3f, 0.3f),     new Rect(0f, 0f, 0.4f, 0.4f),     new Rect(0f, 0f, 0.5f, 0.5f),     new Rect(0f, 0f, 0.6f, 0.6f) },
+        //     new Rect[] { new Rect(0.7f, 0f, 0.3f, 0.3f),   new Rect(0.6f, 0f, 0.4f, 0.4f),   new Rect(0.5f, 0f, 0.5f, 0.5f),   new Rect(0.4f, 0f, 0.6f, 0.6f) },
+        //     new Rect[] { new Rect(0f, 0.7f, 0.3f, 0.3f),   new Rect(0f, 0.6f, 0.4f, 0.4f),   new Rect(0f, 0.5f, 0.5f, 0.5f),   new Rect(0f, 0.4f, 0.6f, 0.6f) },
+        //     new Rect[] { new Rect(0.7f, 0.7f, 0.3f, 0.3f), new Rect(0.6f, 0.6f, 0.4f, 0.4f), new Rect(0.5f, 0.5f, 0.5f, 0.5f), new Rect(0.4f, 0.4f, 0.6f, 0.6f) }
+        //};
+        static Rect[][] LocateAreaData = new Rect[][] {
+             new Rect[] { new Rect(0f, 0f, 0.3f, 0.3f),     new Rect(0f, 0f, 0.4f, 0.4f),     new Rect(0f, 0f, 0.5f, 0.5f)     },
+             new Rect[] { new Rect(0.7f, 0f, 0.3f, 0.3f),   new Rect(0.6f, 0f, 0.4f, 0.4f),   new Rect(0.5f, 0f, 0.5f, 0.5f)   },
+             new Rect[] { new Rect(0f, 0.7f, 0.3f, 0.3f),   new Rect(0f, 0.6f, 0.4f, 0.4f),   new Rect(0f, 0.5f, 0.5f, 0.5f)   },
+             new Rect[] { new Rect(0.7f, 0.7f, 0.3f, 0.3f), new Rect(0.6f, 0.6f, 0.4f, 0.4f), new Rect(0.5f, 0.5f, 0.5f, 0.5f) }
+        };
+        //static bool LocateDebug = false;
+        static bool LocateDebug = true;
+
+        public Geometry2D.Vector<int> Size { get; private set; }
+        public ScreenMap Screen;       // 识别到的屏幕,用于执行透视变换
+
+        int capture = 0;
+        int delay = 0;
+        int maxCapture;
+        int maxDelay;
+
+        Geometry.Vector<float>[] ScreenBlackTexture;
+        Geometry.Vector<float>[] ScreenWhiteTexture;
+        int locateIndex = -1;
+        List<Rect> locateArea = new List<Rect> { 
+            new Rect(0f, 0f, 0.5f, 0.5f), new Rect(0.5f, 0f, 0.5f, 0.5f), new Rect(0f, 0.5f, 0.5f, 0.5f), new Rect(0.5f, 0.5f, 0.5f, 0.5f)
+        };      // 屏幕显示白色的区域大小
+
+        float areaPercent => locateArea[locateIndex].size.x;         // 当前白色区域的占比
+        int areaSelected = -1;                                       // 选择哪个区域,顺序与Quadrilateral对应
+        List<float> sumTemp = new List<float>();
+        List<OrdinalQuadrilateral> quadTemp = new List<OrdinalQuadrilateral>();
+
+        //public ScreenIdentification(WebCamTexture texture)
+        //{
+        //    Size = new Geometry2D.Vector<int>(texture.width, texture.height);
+        //    Screen = new ScreenMap();
+        //}
+        public ScreenIdentification(Texture texture)
+        {
+            Size = new Geometry2D.Vector<int>(texture.width, texture.height);
+            Screen = new ScreenMap();
+        }
+        public ScreenIdentification(Geometry2D.Vector<int> size)
+        {
+            Size = size;
+            Screen = new ScreenMap();
+        }
+
+        public void LocateScreenManual(OrdinalQuadrilateral quad) => Screen.Quad = quad;
+
+        public void LocateScreen(int Capture = 30, int Delay = 30)//frame
+        {
+            if (ScreenLocate.Main.DebugScreenImage != null)     // 测试图片
+            {
+                DebugImage(ScreenLocate.Main.DebugScreenImage);
+                return;
+            }
+
+            delay = Delay;
+            capture = Capture;
+            maxDelay = Delay;
+            maxCapture = Capture;
+
+            ScreenLocate.SetScreen(new Rect(0f, 0f, 1f, 1f), UnityEngine.Color.black);
+            //ScreenLocate.SetScreen(new Rect(0f, 0f, 0.6f, 0.6f), UnityEngine.Color.white);
+        }
+       
+        void DebugImage(Texture2D image)
+        {
+            QuadrilateralFit(out Texture2D LocateTex, out Texture2D DrawLineTex, image);
+            ScreenLocate.DebugTexture(2, LocateTex);
+            ScreenLocate.DebugTexture(3, DrawLineTex);
+            //Debug.Log(quadTemp[0]);
+
+            //var watch = new System.Diagnostics.Stopwatch();
+            //watch.Start();
+            //var times = new List<double>() { 0.0 };
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+            Console.WriteLine($"{TAG} quadTemp.Count:{ quadTemp.Count}");
+#endif
+            if (quadTemp.Count > 0) 
+            {
+                // 透视变换
+                var quad = quadTemp[0];
+                var srcWidth = LocateTex.width;
+                var transformWidth = (int)((quad.B.x - quad.A.x + quad.D.x - quad.C.x) / 2);
+                var transformHeight = (int)((quad.C.y - quad.A.y + quad.D.y - quad.B.y) / 2);
+                var transformTex = new Texture2D(transformWidth, transformHeight);
+                var pt = new ZIMPerspectiveTransform(new OrdinalQuadrilateral(new Vector(0, 0), new Vector(transformWidth, 0), new Vector(0, transformHeight), new Vector(transformWidth, transformHeight)), quad);
+                var dstPixel = new UnityEngine.Color[transformWidth * transformHeight];
+                var srcPixel = LocateTex.GetPixels();
+                Parallel.For(0, transformWidth, (x) =>
+                {
+                    for (int y = 0; y < transformHeight; y++)
+                    {
+                        var index = y * transformWidth + x;
+                        var sampleCoord = pt.TransformRound(x, y);
+                        dstPixel[index] = srcPixel[sampleCoord.y * srcWidth + sampleCoord.x];
+                    }
+                });
+                transformTex.SetPixels(dstPixel);
+                transformTex.Apply();
+                ScreenLocate.DebugTexture(1, transformTex);
+#if (!NDEBUG && DEBUG && ENABLE_LOG)
+                Console.WriteLine($"{TAG} ScreenLocate.DebugTexture 1:{ transformTex.GetNativeTexturePtr()}");
+#endif
+            }
+
+            //times.Add(watch.ElapsedMilliseconds);
+            //UnityEngine.Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
+        }
+
+        public void NextScreen()
+        {
+            // 测试用
+            if (LocateDebug && areaSelected == -1)
+            {
+                LocateAreaData = new Rect[][] { new Rect[] { new Rect(0, 0, 1f, 1f) } };
+                locateIndex = 3;
+                areaSelected = 0;
+                locateArea.AddRange(LocateAreaData[0]);
+            }
+
+            // index从-1开始
+            locateIndex++;
+            if (locateIndex < locateArea.Count)     // 依次点亮屏幕区域
+            {
+                ScreenLocate.SetScreen(locateArea[locateIndex], UnityEngine.Color.white);
+                delay = maxDelay;
+                capture = maxCapture;
+            }
+            else                // 退出屏幕黑白控制
+            {
+                ScreenLocate.SetScreen(null);
+                ScreenLocate.Main.ShowScreen(Screen.Quad);
+                Reset();
+            }
+        }
+
+        void Reset()
+        {
+            delay = 0;
+            capture = 0;
+            ScreenWhiteTexture = null;
+            ScreenBlackTexture = null;
+            locateIndex = -1;
+            areaSelected = -1;
+            locateArea.RemoveRange(4, LocateAreaData[0].Length);
+            quadTemp.Clear();
+            sumTemp.Clear();
+        }
+
+        public void CaptureBlack(Texture2D cam)
+        {
+            if (ScreenBlackTexture == null)
+                ScreenBlackTexture = new Geometry.Vector<float>[Size.x * Size.y];
+            var pixel = cam.GetPixels();
+            Parallel.For(0, Size.x * Size.y, i =>
+            {
+                var ip = pixel[i];
+                ScreenBlackTexture[i] += new Geometry.Vector<float>(ip.r / maxCapture, ip.g / maxCapture, ip.b / maxCapture);
+            });
+        }
+
+        public void CaptureWhite(Texture2D cam)
+        {
+            if (ScreenWhiteTexture == null)
+                ScreenWhiteTexture = new Geometry.Vector<float>[Size.x * Size.y];
+            var pixel = cam.GetPixels();
+            Parallel.For(0, Size.x * Size.y, i =>
+            {
+                var ip = pixel[i];
+                ScreenWhiteTexture[i] += new Geometry.Vector<float>(ip.r / maxCapture, ip.g / maxCapture, ip.b / maxCapture);
+            });
+        }
+
+        public void CaptureStay(Texture2D cam)
+        {
+            if (locateIndex == -1)                      // 屏幕黑色
+            {
+                CaptureBlack(cam);
+            }
+            else                                        // 屏幕部分为白色
+            {
+                CaptureWhite(cam);
+            }
+        }
+
+        public void CaptureEnd()
+        {
+            //Debug.Log("locateIndex: " + locateIndex + ", quad: " + quadTemp.Count);
+            if (locateIndex == -1)
+                return;
+
+            if (locateIndex < 4) 
+            {
+                sumTemp.Add(GetBrightness());
+                ScreenWhiteTexture = null;
+
+                // 选择亮度差最大的区域
+                if (locateIndex == 3)
+                {
+                    areaSelected = sumTemp.MaxIndex();
+                    locateArea.AddRange(LocateAreaData[areaSelected]);
+                }
+            }
+            else if (locateIndex >= 4 && locateIndex < locateArea.Count - 1)
+            {
+                QuadrilateralFit(out _,out _);
+                ScreenWhiteTexture = null;
+            }
+            else
+            {
+                QuadrilateralFit(out Texture2D LocateTex, out Texture2D DrawLineTex);
+                //ScreenLocate.DebugTexture(2, LocateTex);
+               // ScreenLocate.DebugTexture(3, DrawLineTex);
+
+                if (quadTemp.Count != LocateAreaData[0].Length)
+                {
+                    Debug.Log($"拟合四边形失败, quadTemp.Count: {quadTemp.Count}");
+                }
+                else if (quadTemp.Count == 1) 
+                {
+                    Screen.Quad = quadTemp[0];
+                }
+                else
+                {
+                    // 线性拟合
+                    var xValue = new List<float>() { 0 };
+                    var predicts = new List<Vector>();
+                    foreach (var i in LocateAreaData[0])
+                        xValue.Add(i.size.x);
+
+                    Vector baseVertex = Vector.Zero;            // x==0 时的点
+                    {
+                        foreach (var q in quadTemp)
+                        {
+                            baseVertex += q[areaSelected];
+                        }
+                        baseVertex /= quadTemp.Count;
+                    }
+                    double rs = 0.0;
+                    for (int i = 0; i < 4; i++)
+                    {
+                        if (i == areaSelected)
+                        {
+                            predicts.Add(baseVertex);
+                        }
+                        else
+                        {
+                            var yValue = new List<Vector>() { baseVertex };        
+                            foreach (var q in quadTemp)
+                            {
+                                yValue.Add(q[i]);
+                            }    
+                            var lr = LinerRegression1D.Fit(2, xValue.ToArray(), yValue.ToArray());
+                            rs += lr.RSquared / 3;
+                            predicts.Add(lr.Predict<Vector>(1));
+                        }
+                    }
+                    Screen.Quad = new OrdinalQuadrilateral(predicts);
+                    Debug.Log($"[InfraredIdentification2拟合结果] RSquared: {rs}, Quad: {Screen.Quad}");
+                    if (rs < 0.8) Screen.Quad = null;
+                }
+            }
+
+        }
+
+        public bool Update(Texture2D cam)
+        {
+            if (delay != 0)
+            {
+                delay--;
+                return true;
+            }
+            if (capture != 0) 
+            {
+                CaptureStay(cam);
+
+                capture--;
+                if (capture == 0) 
+                {
+                    CaptureEnd();
+                    NextScreen();
+                }
+                return true;
+            }
+
+            return false;
+
+            #region Old
+            /*
+
+
+    if (delay != 0)
+    {
+        delay--;
+        return true;
+    }
+    if (capture != 0)
+    {
+        capture--;
+        if (ScreenBlackTexture == null)
+            ScreenBlackTexture = new Geometry.Vector<float>[Size.x * Size.y];
+        var pixel = cam.GetPixels();
+        Parallel.For(0, Size.x * Size.y, i =>
+        {
+            var ip = pixel[i];
+            ScreenBlackTexture[i] += new Geometry.Vector<float>(ip.r, ip.g, ip.b);
+        });
+        if (capture == 0)
+            ScreenLocate.SetScreen(UnityEngine.Color.black);
+        return true;
+    }
+
+    if (delay != 0)
+    {
+        delay--;
+        return true;
+    }
+    if (capture != 0)
+    {
+        capture--;
+        if (ScreenWhiteTexture == null)
+            ScreenWhiteTexture = new Geometry.Vector<float>[Size.x * Size.y];
+        var pixel = cam.GetPixels();
+        Parallel.For(0, Size.x * Size.y, i =>
+        {
+            var ip = pixel[i];
+            ScreenWhiteTexture[i] += new Geometry.Vector<float>(ip.r, ip.g, ip.b);
+        });
+        if (capture == 0)
+            ScreenLocate.SetScreen(UnityEngine.Color.black);
+        return true;
+    }
+    if (delay != 0)
+    {
+        delay--;
+        return true;
+    }
+    if (capture != 0)
+    {
+        capture--;
+        var pixel = cam.GetPixels();
+        Parallel.For(0, Size.x * Size.y, i =>
+        {
+            var ip = pixel[i];
+            ScreenWhiteTexture[i] -= new Geometry.Vector<float>(ip.r, ip.g, ip.b);
+        });
+        if (capture == 0)
+        {
+            ScreenLocate.SetScreen(null);
+            UnityEngine.Color[] newPixel = new UnityEngine.Color[Size.x * Size.y];
+
+            Parallel.For(0, Size.x * Size.y, i => {
+                var pi = ScreenWhiteTexture[i] /= capture;
+                newPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
+            });
+
+            //读取数据
+            //{
+            //    var fileName = "3.bin";
+            //    ScreenLocateTexture = $"2023 04 16 厦门测试数据/{fileName}".FileReadByte<Vector<float>[]>();
+            //    Debug.Log($"Read {fileName}");
+            //    Parallel.For(0, Size.x * Size.y, i =>
+            //    {
+            //        var pi = ScreenLocateTexture[i];
+            //        newPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
+            //    });
+            //}
+
+            var ScreenLocateTex = new Texture2D(Size.x, Size.y);
+            ScreenLocateTex.SetPixels(newPixel);
+            ScreenLocateTex.Apply();
+            //ScreenLocate.DebugTexture(2, ScreenLocateTex);
+            var ScreenLocateTexLighted = ScreenLocateTex.AutoLight(10);
+
+            //ScreenLocate.DebugTexture(2, ScreenLocateTexLighted);
+            //var FileSavePath = Application.persistentDataPath + "/ScreenLocateTexture.bin";
+            bool Save = ScreenLocate.Main.SaveToggle.isOn;
+            string time;
+            if (Save)
+            {
+                time = DateTime.Now.ToString("yyyyMMdd_HHmmss");
+                var FileSavePath = $"屏幕定位数据{time}.bin";
+                FileSavePath.FileWriteByte(ScreenWhiteTexture);
+
+                var bytes = ScreenLocateTexLighted.EncodeToPNG();
+                File.WriteAllBytes($"屏幕定位数据{time}.png", bytes);
+
+                Debug.Log("ScreenLocateTexture Saved To: " + FileSavePath);
+            }
+
+            var ScreenLocateTexR = ScreenLocateTexLighted.ToRGB(ColorChannel.Red);
+            var ScreenLocateTexG = ScreenLocateTexLighted.ToRGB(ColorChannel.Green);
+            var ScreenLocateTexB = ScreenLocateTexLighted.ToRGB(ColorChannel.Blue);
+            ScreenLocate.DebugTexture(2, ScreenLocateTexR);
+            //ScreenLocate.DebugTexture(4, ScreenLocateTexG);
+            //ScreenLocate.DebugTexture(5, ScreenLocateTexB);
+
+
+            var watch = new System.Diagnostics.Stopwatch();
+            watch.Start();
+            var times = new List<double>() { 0.0 };
+
+
+
+            var ScreenLocateTexLightedMat = ScreenLocateTexLighted.Too0Mat();
+            //var ScreenLocateTexLightedMat = texture.Too0Mat();
+
+            //var (edge, edgeDir) = ScreenLocateTexLightedMat.IdentifyEdge();
+            var (edge, edgeDir) = ScreenLocateTexLightedMat.zimIdentifyEdgeGradientAny(15);
+            //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradient().ToTex());
+            //ScreenLocate.DebugTexture(4, edge.ToTex());
+
+            var quadLines = ScreenLocateTexLightedMat.IdentifyQuadLSD(edge, edgeDir, out List<Line> lightLines, 30);
+            var drawLineMap = new MatrixF2D(edge..Size.x, edge.Size.y);
+            int lineCount = 0;
+            foreach (var l in quadLines)
+            {
+                if (l != null)
+                {
+                    drawLineMap.DrawLine(l, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
+                    lineCount++;
+                }
+            }
+            if (lineCount == 4)
+            {
+                var a = quadLines[0].Intersect(quadLines[3], false).Value;
+                var b = quadLines[0].Intersect(quadLines[1], false).Value;
+                var c = quadLines[2].Intersect(quadLines[3], false).Value;
+                var d = quadLines[1].Intersect(quadLines[2], false).Value;
+                Quad = new Quadrilateral(a, b, c, d);
+                if (!Quad.IsInScreen(ScreenLocate.Main.WebCamera.Size))
+                    Quad = null;
+            }
+            ScreenLocate.Main.ShowScreen(Quad);
+
+            //var lines = edge.IdentifyLineLSD(edgeDir, 100);
+            ////var lines = ScreenLocateTexLightedMat.IdentifyLineLSD();
+
+            //var drawLineMap = new MatrixF2D(edge..Size.x, edge.Size.y);
+            //var returnMaxLines = lines.Sub(0, 10);
+            //foreach (var (line, sum, gradient) in returnMaxLines)
+            //    drawLineMap.DrawLine(line, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
+
+
+            ScreenLocate.DebugTexture(3, drawLineMap.ToTex());
+            //{
+            //    var bytes = drawLineMap.ToTex().EncodeToPNG();
+            //    File.WriteAllBytes($"屏幕定位数据DrawLineMap.png", bytes);
+            //}
+
+
+            times.Add(watch.ElapsedMilliseconds);
+            UnityEngine.Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
+
+            //ScreenLocate.DebugTexture(5, edge.IdentifyLine(edgeDir).ToTex());
+            //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientX().ToTex());
+            //ScreenLocate.DebugTexture(5, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientY().ToTex());
+
+            //var convolutionLighted2 = ScreenLocateTexLighted.Too0Mat().IdentifyEdgeVariance().ToTex();
+
+            // opecncv处理
+            // zim
+            {
+                //var cvLines = edge.cvHoughLinesP();
+                //ScreenLocate.DebugTexture(5, cvLines);
+
+                //var myLines = Hough.Transform(edgeMat);
+                //var cvLines = edge.cvLine(myLines);
+                //ScreenLocate.DebugTexture(5, cvLines);
+            }
+
+            UnityEngine.Object.Destroy(ScreenLocateTex);
+
+
+            //ScreenLocate.DebugTexture(4, convolutionLighted2);
+        }
+
+        return true;
+    }
+
+    /*
+    var avg = new Geometry4D.Vector<float>();
+    var pixel = texture.GetPixels();
+    foreach(var i in pixel.Index())
+    {
+        var iP = pixel[i];
+        avg += new Geometry4D.Vector<float>(iP.r, iP.g, iP.b, iP.a);
+    }
+    avg /= pixel.Count();
+
+    /*
+    var (texLightedR, texLightedG, texLightedB) = ToRGB(newTex);
+    ScreenLocate.DebugTexture(3, texLightedR);
+    ScreenLocate.DebugTexture(4, texLightedG);
+    ScreenLocate.DebugTexture(5, texLightedB);
+    //Debug.Log(avg);
+
+    return false;
+
+/**/
+            #endregion
+
+
+        }
+
+        float GetBrightness()
+        {
+            UnityEngine.Color[] differPixel = new UnityEngine.Color[Size.x * Size.y];
+
+            Parallel.For(0, Size.x * Size.y, i => {
+                var pi = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
+                differPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
+            });
+
+            var sum = 0f;
+            foreach (var i in differPixel)
+            {
+                sum += i.Brightness();
+            }
+            sum /= differPixel.Length;
+            //Debug.Log(sum);
+            return sum;
+        }
+
+        void QuadrilateralFit(out Texture2D LocateTex, out Texture2D DrawLineTex, Texture2D debugImage = null)
+        {
+            OrdinalQuadrilateral quad = null;
+            UnityEngine.Color[] differPixel = new UnityEngine.Color[Size.x * Size.y];
+
+            //读取数据
+            if (debugImage != null) 
+            {
+                Debug.Log($"Debug {debugImage.name}");
+                differPixel = debugImage.GetPixels();
+            }
+            else    // 获得屏幕差值
+            {
+                Parallel.For(0, Size.x * Size.y, i => {
+                    var pi = ScreenWhiteTexture[i] - ScreenBlackTexture[i];
+                    differPixel[i] = new UnityEngine.Color(pi.x, pi.y, pi.z);
+                });
+            }
+
+            var ScreenLocateTex = new Texture2D(Size.x, Size.y);
+            ScreenLocateTex.SetPixels(differPixel);
+            ScreenLocateTex.Apply();
+            //ScreenLocate.DebugTexture(2, ScreenLocateTex);
+            var ScreenLocateTexLighted = ScreenLocateTex.AutoLight(10);
+
+            //ScreenLocate.DebugTexture(2, ScreenLocateTexLighted);
+
+            var ScreenLocateTexR = ScreenLocateTexLighted.ToRGB(ColorChannel.Red);
+            var ScreenLocateTexG = ScreenLocateTexLighted.ToRGB(ColorChannel.Green);
+            var ScreenLocateTexB = ScreenLocateTexLighted.ToRGB(ColorChannel.Blue);
+
+            LocateTex = ScreenLocateTexR;
+            //ScreenLocate.DebugTexture(2, ScreenLocateTexR);
+            //ScreenLocate.DebugTexture(4, ScreenLocateTexG);
+            //ScreenLocate.DebugTexture(5, ScreenLocateTexB);
+
+
+            //var watch = new System.Diagnostics.Stopwatch();
+            //watch.Start();
+            //var times = new List<double>() { 0.0 };
+
+
+
+            var ScreenLocateTexLightedMat = ScreenLocateTexLighted.Too0Mat();
+            //var ScreenLocateTexLightedMat = texture.Too0Mat();
+
+            //var (edge, edgeDir) = ScreenLocateTexLightedMat.IdentifyEdge();
+            int conSize = 15;
+            var (edge, edgeDir) = ScreenLocateTexLightedMat.zimIdentifyEdgeGradientAny(conSize);
+            //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradient().ToTex());
+            //ScreenLocate.DebugTexture(4, edge.ToTex());
+
+            var minLength = locateIndex == -1 ? 50 : 50 * areaPercent;
+            var quadLines = ScreenLocateTexLightedMat.ZIMIdentifyQuadLSD(edge, edgeDir, out List<Line> lightLines, conSize, minLength);
+            var drawLineMap = new Matrix(edge.Size, Tiling: true);
+            int lineCount = 0;
+            foreach (var l in quadLines)
+            {
+                if (l != null)
+                {
+                    drawLineMap.DrawLine(l, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
+                    lineCount++;
+                }
+            }
+            //foreach (var l in lightLines)
+            //{
+            //    if (l != null)
+            //    {
+            //        if (quadLines.Contains(l))
+            //        {
+            //            drawLineMap.DrawLine(l, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
+            //            lineCount++;
+            //        }
+            //        else
+            //        {
+            //            drawLineMap.DrawLine(l, (x, y) => 1, new Geometry2D.Float.Vector(0, 2));
+            //        }
+            //    }
+            //}
+            if (lineCount == 4)
+            {
+                var a = quadLines[0].Intersect(quadLines[3], false).Value;
+                var b = quadLines[0].Intersect(quadLines[1], false).Value;
+                var c = quadLines[2].Intersect(quadLines[3], false).Value;
+                var d = quadLines[1].Intersect(quadLines[2], false).Value;
+                quad = new OrdinalQuadrilateral(a, b, c, d);
+                if (!quad.IsInScreen(ScreenLocate.Main.mUVCCameraInfo.Size))
+                    quad = null;
+            }
+            //if (quad != null && debugImage == null)
+            if (quad != null)
+                quadTemp.Add(quad);
+
+            //var lines = edge.IdentifyLineLSD(edgeDir, 100);
+            ////var lines = ScreenLocateTexLightedMat.IdentifyLineLSD();
+
+            //var drawLineMap = new MatrixF2D(edge..Size.x, edge.Size.y);
+            //var returnMaxLines = lines.Sub(0, 10);
+            //foreach (var (line, sum, gradient) in returnMaxLines)
+            //    drawLineMap.DrawLine(line, (x, y) => 1, new Geometry2D.Float.Vector(0, 10));
+
+            DrawLineTex = drawLineMap.ToTex();
+            //ScreenLocate.DebugTexture(3, drawLineMap.ToTex());
+            //var FileSavePath = Application.persistentDataPath + "/ScreenLocateTexture.bin";
+            bool Save = ScreenLocate.Main.SaveToggle.isOn;
+            string time;
+            if (Save)
+            {
+                time = DateTime.Now.ToString("yyyyMMdd_HHmmss");
+                var FileSavePath = $"{time}屏幕定位数据.bin";
+                FileSavePath.FileWriteByte(ScreenWhiteTexture);
+
+                var bytes = ScreenLocateTexLighted.EncodeToPNG();
+                File.WriteAllBytes($"{time}屏幕.png", bytes);
+                bytes = DrawLineTex.EncodeToPNG();
+                File.WriteAllBytes($"{time}屏幕边框识别.png", bytes);
+                Debug.Log("ScreenLocateTexture Saved To: " + FileSavePath);
+            }
+
+            //times.Add(watch.ElapsedMilliseconds);
+            //UnityEngine.Debug.Log("time: " + (times[times.Count - 1] - times[times.Count - 2]));
+
+            //ScreenLocate.DebugTexture(5, edge.IdentifyLine(edgeDir).ToTex());
+            //ScreenLocate.DebugTexture(4, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientX().ToTex());
+            //ScreenLocate.DebugTexture(5, ScreenLocateTexLighted.Too0Mat().IdentifyEdgeGradientY().ToTex());
+
+            //var convolutionLighted2 = ScreenLocateTexLighted.Too0Mat().IdentifyEdgeVariance().ToTex();
+
+            // opecncv处理
+            // zim
+            {
+                //var cvLines = edge.cvHoughLinesP();
+                //ScreenLocate.DebugTexture(5, cvLines);
+
+                //var myLines = Hough.Transform(edgeMat);
+                //var cvLines = edge.cvLine(myLines);
+                //ScreenLocate.DebugTexture(5, cvLines);
+            }
+
+            UnityEngine.Object.Destroy(ScreenLocateTex);
+        }
+    }
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/ScreenIdentification.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5747889e57a4939448e95ebce8eca489
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 72 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/ScreenMap.cs

@@ -0,0 +1,72 @@
+using o0.Geometry2D.Float;
+using System;
+using System.Diagnostics;
+using UnityEngine;
+
+namespace ZIM.Unity
+{
+    // 记录屏幕的位置,Quad表示屏幕4个点的坐标
+    // TransformToScreen可将摄像机空间的点映射到屏幕空间,反之用TransformToCamera
+    public class ScreenMap
+    {
+        public Rect QuadRect { get; private set; }
+        public Vector2 UVSize { get; private set; }     // UV代表屏幕空间的坐标,UVSize代表屏幕坐标的取值范围
+        public bool Active => quad != null;
+        
+
+        public OrdinalQuadrilateral Quad
+        {
+            get => quad;
+            set
+            {
+                quad = value;
+                if (value != null)
+                {
+                    var x = Math.Min((value.A - value.B).Length, (value.C - value.D).Length);
+                    var y = Math.Min((value.A - value.C).Length, (value.B - value.D).Length);
+                    UVSize = new Vector2(x, y);
+                    perspective = new ZIMPerspectiveTransform(value, new OrdinalQuadrilateral(new Vector(0, 0), new Vector(x, 0), new Vector(0, y), new Vector(x, y)));
+
+                    var aabb = value.AABBRect();
+                    QuadRect = new Rect(aabb.Item1.x, aabb.Item1.y, aabb.Item2.x - aabb.Item1.x, aabb.Item2.y - aabb.Item1.y);
+                    //Debug.Log(QuadRect);
+                }
+            }
+        }
+        OrdinalQuadrilateral quad;
+        ZIMPerspectiveTransform perspective;
+
+        public ScreenMap()
+        {
+
+        }
+
+        public ScreenMap(OrdinalQuadrilateral quad)
+        {
+            Quad = quad;
+        }
+
+        public bool UVInScreen(Vector2 v)
+        {
+            return v.x > 0 && v.x < UVSize.x && v.y > 0 && v.y < UVSize.y;
+        }
+
+        // UV归一化到[0, 1]范围,仅用于输出最终结果
+        public Vector2 UVNormalize(Vector2 location)
+        {
+            return new Vector2(location.x / UVSize.x, location.y / UVSize.y);
+        }
+
+        public Vector2 TransformToScreen(Vector2 vIn)
+        {
+            var v = perspective.Transform(vIn.x, vIn.y);
+            return new Vector2(v.x, v.y);
+        }
+
+        public Vector2 TransformToCamera(Vector2 vIn)
+        {
+            var v = perspective.TransformInverse(vIn.x, vIn.y);
+            return new Vector2(v.x, v.y);
+        }
+    }
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/ScreenMap.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 28a800355e2b19d4e9cfa2b3077372d7
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 74 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/SimpleLocationEstimation.cs

@@ -0,0 +1,74 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnscentedKalmanFilter;
+
+namespace ZIM
+{
+    // 固定时间间隔下,预测位置轨迹
+    public class SimpleLocationEstimation
+    {
+        //public bool Initialized;
+        public Vector2 Predict;
+
+        Vector2 LastLocation;
+        Vector2 LastSpeed;
+        Vector2 LastAcc;
+        float AccChangeScale;
+        List<Vector2> Locations;
+
+        // 卡尔曼滤波作用于速度
+        UKF filterx;
+        UKF filtery;
+
+        public SimpleLocationEstimation(float accChangeScale = 1)
+        {
+            Locations = new List<Vector2>();
+            AccChangeScale = accChangeScale;
+            filterx = new UKF();
+            filtery = new UKF();
+        }
+
+        public Vector2 Update(Vector2 loc)
+        {
+            if (Locations == null)
+            {
+                var newSpeed = loc - LastLocation;
+                var newAcc = newSpeed - LastSpeed;
+                var accPredict = newAcc + (newAcc - LastAcc) * AccChangeScale;
+                var speedPredict = newSpeed + accPredict;
+                //if (speedPredict.x * newSpeed.x < 0)
+                //    speedPredict.x = 0;
+                //if (speedPredict.y * newSpeed.y < 0)
+                //    speedPredict.y = 0;
+                //var LocationPredict = loc + speedPredict;
+
+                filterx.Update(new double[] { speedPredict.x });
+                filtery.Update(new double[] { speedPredict.y });
+
+                var LocationPredict = loc + new Vector2((float)filterx.getState()[0], (float)filtery.getState()[0]);
+
+                LastSpeed = newSpeed;
+                LastAcc = newAcc;
+                LastLocation = loc;
+                return Predict = LocationPredict;
+                //return Predict = new Vector2((float)filterx.getState()[0], (float)filtery.getState()[0]);
+            }
+            if (Locations.Count < 2)
+            {
+                Locations.Add(loc);
+            }
+            else
+            {
+                Locations.Add(loc);
+                var speed = new Vector2[] { Locations.ElementAt(1) - Locations.ElementAt(0), Locations.ElementAt(2) - Locations.ElementAt(1) };
+                LastLocation = loc;
+                LastSpeed = speed[1];
+                LastAcc = speed[1] - speed[0];
+                Locations = null;
+            }
+            return Predict = loc;
+        }
+
+    }
+}

+ 11 - 0
Assets/WebCamera/Script/ZIM/InfraredLocate/SimpleLocationEstimation.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 93f7b0cb95588c44a9d26ddd586d4665
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Some files were not shown because too many files changed in this diff