StereoApplication.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Threading.Tasks;
  5. using Urho.Resources;
  6. namespace Urho.SharpReality
  7. {
  8. public class StereoApplication : Application
  9. {
  10. Matrix4 leftView = Matrix4.Identity;
  11. Matrix4 leftProj = Matrix4.Identity;
  12. Matrix4 rightView = Matrix4.Identity;
  13. Matrix4 rightProj = Matrix4.Identity;
  14. float yaw;
  15. float pitch;
  16. float distanceBetweenEyes;
  17. public bool Emulator { get; set; }
  18. public Scene Scene { get; private set; }
  19. public Octree Octree { get; private set; }
  20. public Zone Zone { get; private set; }
  21. public Camera LeftCamera { get; set; }
  22. public Camera RightCamera { get; set; }
  23. public Camera CullingCamera { get; set; }
  24. public Light DirectionalLight { get; set; }
  25. public virtual Vector3 FocusWorldPoint { get; set; }
  26. public float DistanceBetweenEyes
  27. {
  28. get
  29. {
  30. if (distanceBetweenEyes == 0 && !Emulator)
  31. {
  32. var l = LeftCamera.Node.WorldPosition;
  33. var r = RightCamera.Node.WorldPosition;
  34. distanceBetweenEyes = (float)Math.Sqrt((r.X-l.X)*(r.X-l.X)+(r.Y-l.Y)*(r.Y-l.Y)+(r.Z-l.Z)*(r.Z-l.Z));
  35. }
  36. return distanceBetweenEyes;
  37. }
  38. }
  39. public Vector3 HeadPosition
  40. {
  41. get
  42. {
  43. var leftCameraNode = LeftCamera.Node.WorldPosition;
  44. if (Emulator) return leftCameraNode;
  45. leftCameraNode.X += DistanceBetweenEyes / 2;
  46. return leftCameraNode;
  47. }
  48. }
  49. public bool EnableGestureTapped { get; set; }
  50. public bool EnableGestureHold { get; set; }
  51. public bool EnableGestureManipulation { get; set; }
  52. protected StereoApplication(ApplicationOptions opts) : base(opts) { }
  53. protected override void OnUpdate(float timeStep)
  54. {
  55. if (Emulator)
  56. EmulateCamera(timeStep);
  57. base.OnUpdate(timeStep);
  58. }
  59. void EmulateCamera(float timeStep, float moveSpeed = 2.0f)
  60. {
  61. const float mouseSensitivity = .1f;
  62. if (UI.FocusElement != null)
  63. return;
  64. var mouseMove = Input.MouseMove;
  65. yaw += mouseSensitivity * mouseMove.X;
  66. pitch += mouseSensitivity * mouseMove.Y;
  67. pitch = MathHelper.Clamp(pitch, -90, 90);
  68. var cameraNode = LeftCamera.Node;
  69. cameraNode.Rotation = new Quaternion(pitch, yaw, 0);
  70. if (Input.GetKeyDown(Key.W)) cameraNode.Translate( Vector3.UnitZ * moveSpeed * timeStep);
  71. if (Input.GetKeyDown(Key.S)) cameraNode.Translate(-Vector3.UnitZ * moveSpeed * timeStep);
  72. if (Input.GetKeyDown(Key.A)) cameraNode.Translate(-Vector3.UnitX * moveSpeed * timeStep);
  73. if (Input.GetKeyDown(Key.D)) cameraNode.Translate( Vector3.UnitX * moveSpeed * timeStep);
  74. }
  75. protected virtual XmlFile DefaultRenderPath => CoreAssets.RenderPaths.Forward;
  76. [DllImport(Consts.NativeImport, CallingConvention = CallingConvention.Cdecl)]
  77. static extern void Camera_SetHoloProjections(
  78. IntPtr leftEyeCamera, IntPtr rightEyeCamera, IntPtr cullingCamera,
  79. ref Matrix4 leftView, ref Matrix4 leftProjection,
  80. ref Matrix4 rightView, ref Matrix4 rightProjection);
  81. protected override void Start()
  82. {
  83. Renderer.SetDefaultRenderPath(DefaultRenderPath);
  84. Renderer.DrawShadows = false;
  85. Scene = new Scene();
  86. Octree = Scene.CreateComponent<Octree>();
  87. Zone = Scene.CreateComponent<Zone>();
  88. Zone.AmbientColor = new Color(0.5f, 0.5f, 0.5f);
  89. Node lightNode = Scene.CreateChild();
  90. lightNode.SetDirection(new Vector3(0.5f, -1, 1));
  91. DirectionalLight = lightNode.CreateComponent<Light>();
  92. DirectionalLight.LightType = LightType.Directional;
  93. DirectionalLight.CastShadows = false;
  94. DirectionalLight.Brightness = 0.7f;
  95. Renderer.TextureAnisotropy = 0;
  96. Renderer.TextureFilterMode = TextureFilterMode.Bilinear;
  97. var leftCameraNode = Scene.CreateChild();
  98. var rightCameraNode = Scene.CreateChild();
  99. LeftCamera = leftCameraNode.CreateComponent<Camera>();
  100. RightCamera = rightCameraNode.CreateComponent<Camera>();
  101. if (Emulator)
  102. {
  103. LeftCamera.Fov = 30;
  104. LeftCamera.NearClip = 0.1f;
  105. LeftCamera.FarClip = 20f;
  106. LeftCamera.AspectRatio = 1.76f;
  107. return;
  108. }
  109. Renderer.NumViewports = 2; //two eyes
  110. #if UWP_HOLO
  111. var leftViewport = new Viewport(Scene, LeftCamera, null);
  112. var rightVp = new Viewport(Scene, RightCamera, null);
  113. Renderer.SetViewport(0, leftViewport);
  114. Renderer.SetViewport(1, rightVp);
  115. var cullingCameraNode = Scene.CreateChild();
  116. CullingCamera = cullingCameraNode.CreateComponent<Camera>();
  117. rightVp.CullCamera = CullingCamera;
  118. leftViewport.CullCamera = CullingCamera;
  119. rightVp.SetStereoMode(true);
  120. Time.SubscribeToFrameStarted(args =>
  121. Camera_SetHoloProjections(
  122. LeftCamera.Handle, RightCamera.Handle, CullingCamera.Handle,
  123. ref leftView, ref leftProj,
  124. ref rightView, ref rightProj));
  125. #else
  126. var leftEyeRect = new IntRect(0, 0, Graphics.Width / 2, Graphics.Height);
  127. var rightEyeRect = new IntRect(Graphics.Width / 2, 0, Graphics.Width, Graphics.Height);
  128. var leftViewport = new Viewport(Scene, LeftCamera, leftEyeRect, null);
  129. var rightVp = new Viewport(Scene, RightCamera, rightEyeRect, null);
  130. Renderer.SetViewport(0, leftViewport);
  131. Renderer.SetViewport(1, rightVp);
  132. leftCameraNode.Translate(new Vector3(-0.032f, 0, 0));
  133. rightCameraNode.Translate(new Vector3(0.032f, 0, 0));
  134. #endif
  135. }
  136. internal void UpdateStereoView(Matrix4 leftView, Matrix4 rightView, Matrix4 leftProj, Matrix4 rightProj)
  137. {
  138. this.leftView = leftView;
  139. this.rightView = rightView;
  140. this.leftProj = leftProj;
  141. this.rightProj = rightProj;
  142. }
  143. public Dictionary<string, Action> CortanaCommands { get; private set; }
  144. /// <summary>
  145. /// NOTE: Make sure "Microphone" capability is declared.
  146. /// </summary>
  147. protected Task<bool> RegisterCortanaCommands(Dictionary<string, Action> commands)
  148. {
  149. CortanaCommands = commands;
  150. #if UWP_HOLO
  151. return Urho.SharpReality.UrhoAppView.Current.VoiceManager.RegisterCortanaCommands(commands);
  152. #else
  153. return Task.FromResult<bool>(false);
  154. #endif
  155. }
  156. public Task TextToSpeech(string text)
  157. {
  158. #if UWP_HOLO
  159. return Urho.SharpReality.UrhoAppView.Current.VoiceManager.TextToSpeech(text);
  160. #else
  161. return Task.FromResult<bool>(false);
  162. #endif
  163. }
  164. /// <summary>
  165. /// NOTE: Make sure "spatialMapping" capability is declared.
  166. /// </summary>
  167. protected Task<bool> StartSpatialMapping(Vector3 extents, int trianglesPerCubicMeter = 1000, Color color = default(Color), bool onlyAdd = false, bool convertToLeftHanded = true)
  168. {
  169. #if UWP_HOLO
  170. var appView = Urho.SharpReality.UrhoAppView.Current;
  171. appView.SpatialMappingManager.DefaultColor = color;
  172. return appView.SpatialMappingManager.Register(this,
  173. appView.ReferenceFrame.CoordinateSystem,
  174. new System.Numerics.Vector3(extents.X, extents.Y, extents.Z),
  175. trianglesPerCubicMeter, onlyAdd, convertToLeftHanded);
  176. #else
  177. return Task.FromResult<bool>(false);
  178. #endif
  179. }
  180. protected void StopSpatialMapping()
  181. {
  182. #if UWP_HOLO
  183. Urho.SharpReality.UrhoAppView.Current.SpatialMappingManager.Stop();
  184. #endif
  185. }
  186. public virtual void OnGestureTapped() { }
  187. public virtual void OnGestureDoubleTapped() { }
  188. public virtual void OnGestureHoldStarted() { }
  189. public virtual void OnGestureHoldCompleted() { }
  190. public virtual void OnGestureHoldCanceled() { }
  191. public virtual void OnGestureManipulationStarted() { }
  192. public virtual void OnGestureManipulationUpdated(Vector3 relativeHandPosition) { }
  193. public virtual void OnGestureManipulationCompleted(Vector3 relativeHandPosition) { }
  194. public virtual void OnGestureManipulationCanceled() { }
  195. public virtual void OnSurfaceAddedOrUpdated(SpatialMeshInfo surface, Model generatedModel) { }
  196. /// <summary>
  197. /// NOTE: called from a background thread
  198. /// </summary>
  199. public virtual Model GenerateModelFromSpatialSurface(SpatialMeshInfo surface)
  200. {
  201. return CreateModelFromVertexData(surface.VertexData, surface.IndexData, surface.BoundsRotation);
  202. }
  203. internal void HandleSurfaceUpdated(SpatialMeshInfo surface)
  204. {
  205. var model = GenerateModelFromSpatialSurface(surface);
  206. InvokeOnMain(() => OnSurfaceAddedOrUpdated(surface, model));
  207. }
  208. protected unsafe Model CreateModelFromVertexData(SpatialVertex[] vertexData, short[] indexData, Quaternion rotation = default(Quaternion))
  209. {
  210. var model = new Model();
  211. var vertexBuffer = new VertexBuffer(Context, false);
  212. var indexBuffer = new IndexBuffer(Context, false);
  213. var geometry = new Geometry();
  214. vertexBuffer.Shadowed = true;
  215. vertexBuffer.SetSize((uint) vertexData.Length, ElementMask.Position | ElementMask.Normal | ElementMask.Color , false);
  216. BoundingBox boundingBox;
  217. if (rotation != default(Quaternion))
  218. {
  219. boundingBox = new BoundingBox();
  220. for (int i = 0; i < vertexData.Length; i++)
  221. {
  222. var position = rotation * vertexData[i].Position;
  223. vertexData[i].Position = position;
  224. boundingBox.Merge(position);
  225. var normal = rotation * vertexData[i].Normal;
  226. vertexData[i].Normal = normal;
  227. }
  228. }
  229. else
  230. {
  231. boundingBox = new BoundingBox(-Vector3.One * 1.26f, Vector3.One * 1.26f);
  232. }
  233. fixed (SpatialVertex* p = &vertexData[0])
  234. vertexBuffer.SetData((void*) p);
  235. indexBuffer.Shadowed = true;
  236. indexBuffer.SetSize((uint)indexData.Length, false, false);
  237. indexBuffer.SetData(indexData);
  238. geometry.SetVertexBuffer(0, vertexBuffer);
  239. geometry.IndexBuffer = indexBuffer;
  240. geometry.SetDrawRange(PrimitiveType.TriangleList, 0, (uint)indexData.Length, 0,(uint) vertexData.Length, true);
  241. model.NumGeometries = 1;
  242. model.SetGeometry(0, 0, geometry);
  243. model.BoundingBox = boundingBox;
  244. return model;
  245. }
  246. }
  247. }