UDMeshCollider.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. using System.Collections;
  2. using System;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using udSDK;
  6. /*
  7. *
  8. */
  9. [System.Serializable]
  10. public class UDMeshCollider : MonoBehaviour
  11. {
  12. [Tooltip("target object to follow")]
  13. public GameObject followTarget = null;
  14. [Tooltip("Determines whether to update the plane only when the target moves a threshold distance from the watcher point")]
  15. public bool threshholdFollow = false;
  16. [Tooltip("Distance from which to update the plane location when threshold follow is turned on")]
  17. public double followThreshold;
  18. [Tooltip("Position of the virtual watcher camera relative to the target")]
  19. public Vector3 watcherPosition = new Vector3(0, 25, 0);
  20. //UDS Renderer components:
  21. private udRenderContext vRenderer;
  22. private udRenderTarget renderView;
  23. //Properties of the plane:
  24. [Tooltip("Width of the collision plane in metres")]
  25. public float width = 10; //width of the plane in metres
  26. [Tooltip("Height of the collision plane in metres")]
  27. public float height = 10; //height of the plane in meters
  28. [Tooltip("position of the near clipping plane along the z axis")]
  29. public float zNear = 0; //location of the near clipping plane
  30. [Tooltip("position of the far clipping plane along the z axis")]
  31. public float zFar = 50; //location of the far plane
  32. [Tooltip("width of the polygon sheet in number of vertices (this is also the resolution of the view)")]
  33. public int widthPix = 50;
  34. [Tooltip("Height of the polygon sheet in number of vertices (this is also the resolution of the view)")]
  35. public int heightPix = 50;
  36. [Tooltip("Turns on smoothing of collider surface")]
  37. public bool laplacianSmoothing = false;
  38. [Tooltip("Determines if the collider rotates with the body of the target object")]
  39. public LockRotationToBody lockRotationToBody;
  40. public Vector3 bodyLockOffset = new Vector3( 0, 0, 0);
  41. [System.Serializable]
  42. public class LockRotationToBody {
  43. public bool x = false;
  44. public bool y = false;
  45. public bool z = false;
  46. };
  47. [Tooltip("If this is true then the mesh is not updated with time: moving point clouds or moving the object will not change the shape of the collider")]
  48. public bool isStaticMesh = false;
  49. [Tooltip("This will cause the program to pause as the collider loads in point cloud information; this will prevent false collisions with incomplete LODS but may cause stuttering with slow connections or large numbers of seperated colliders")]
  50. public bool blockOnStream = true;
  51. Transform previousTransform;
  52. public float[] depthBuffer;
  53. private Color32[] colourBuffer;
  54. void Awake()
  55. {
  56. SetRenderView();
  57. Update();
  58. }
  59. /*
  60. * converts the z buffer value to a world space displacement
  61. */
  62. float zBufferToDepth(float z)
  63. {
  64. return UDUtilities.zBufferToDepth(z, zNear, zFar);
  65. }
  66. /*
  67. * constructs a mesh of world size width x height in metres, each vertex's z dimension is set according to the contents of the z buffer
  68. * triangles are declared in a clockwise direction so face normals are back towards the generating camera
  69. */
  70. private void MakeSheetMesh(double width, double height, int numVertsX, int numVertsY, float[] depthMap = null)
  71. {
  72. Vector3[] verts;
  73. Vector3[] norms = new Vector3[numVertsX * numVertsY];
  74. Vector2[] uv = new Vector2[numVertsX * numVertsY];
  75. List<int> tris = new List<int>(numVertsX * numVertsY * 3);
  76. //initialise a mesh plane centred at origin
  77. verts = new Vector3[numVertsX * numVertsY];
  78. double xSpacing = width / numVertsX;
  79. double ySpacing = height / numVertsY;
  80. int triCount = 0;
  81. for (int i = 0; i < numVertsY; i++)
  82. {
  83. for (int j = 0; j < numVertsX; j++)
  84. {
  85. float zPrime = depthMap == null ? 0f : depthMap[i * numVertsX + j];
  86. float depth = zBufferToDepth(zPrime);
  87. uv[i * numVertsX + j] = new Vector2(j / (float)numVertsX, i / (float)numVertsY);
  88. verts[numVertsX * i + j] = new Vector3((float)(j * xSpacing - width / 2), (float)(i * ySpacing - height / 2), -depth);
  89. if (((i + j) % 2 == 0))
  90. {
  91. //make triangles at every interior even vert
  92. if (i > 0 && j > 0)
  93. {
  94. tris.Add(numVertsX * i + j); //current vertex
  95. tris.Add(numVertsX * i + j - 1); //vertex left
  96. tris.Add(numVertsX * (i - 1) + j); //vertex above
  97. triCount++;
  98. }
  99. if (i > 0 && j < numVertsX - 1)
  100. {
  101. tris.Add(numVertsX * i + j); //current vertex
  102. tris.Add(numVertsX * (i - 1) + j); //vertex above
  103. tris.Add(numVertsX * i + j + 1); //vertex Right
  104. triCount++;
  105. }
  106. if (j < (numVertsX - 1) && i < (numVertsY - 1))
  107. {
  108. tris.Add(numVertsX * i + j); //current vertex
  109. tris.Add(numVertsX * i + j + 1); //vertex Right
  110. tris.Add(numVertsX * (i + 1) + j); //vertex below
  111. triCount++;
  112. }
  113. if (i < numVertsY - 1 && j > 0)
  114. {
  115. tris.Add(numVertsX * i + j); //current vertex
  116. tris.Add(numVertsX * (i + 1) + j); //vertex below
  117. tris.Add(numVertsX * i + j - 1); //vertex left
  118. triCount++;
  119. }
  120. }
  121. }
  122. }
  123. if (laplacianSmoothing)
  124. verts = LaplacianSmooth(verts, numVertsX, numVertsY);
  125. Mesh mesh = new Mesh();
  126. mesh.vertices = verts;
  127. mesh.uv = uv;
  128. mesh.triangles = tris.ToArray();
  129. MeshFilter mf = GetComponent<MeshFilter>();
  130. if (mf != null)
  131. mf.mesh = mesh;
  132. GetComponent<MeshCollider>().sharedMesh = mesh;
  133. }
  134. /*
  135. * Currently unused, moves the mesh vertices towards and away from the camera with the sine of time
  136. */
  137. private void WarpMesh()
  138. {
  139. Mesh mesh = GetComponent<MeshFilter>().mesh;
  140. Vector3[] vertices = mesh.vertices;
  141. for (int i = 0; i < vertices.Length; i++)
  142. vertices[i] = vertices[i] + new Vector3(0, 0, Mathf.Sin(Time.time));
  143. mesh.vertices = vertices;
  144. GetComponent<MeshCollider>().sharedMesh = mesh;
  145. }
  146. /*
  147. *Laplacian smoothing operation, each vertex is modified such that it is the average of its neighbours
  148. */
  149. private Vector3[] LaplacianSmooth(Vector3[] verts, int numVertsX, int numVertsY)
  150. {
  151. Vector3[] newVerts = new Vector3[numVertsX * numVertsY];
  152. for (int i = 0; i < numVertsY; i++)
  153. {
  154. for (int j = 0; j < numVertsX; j++)
  155. {
  156. float sumNeighbours = 0;
  157. float numNeighbours = 0;
  158. if (i > 0 && j > 0)
  159. {
  160. //node to the left and above
  161. float neighbour = verts[(i - 1) * numVertsX + j - 1].z;
  162. sumNeighbours += neighbour;
  163. numNeighbours++;
  164. }
  165. if (i > 0)
  166. {
  167. //node to the left
  168. float neighbour = verts[(i - 1) * numVertsX + j].z;
  169. sumNeighbours += neighbour;
  170. numNeighbours++;
  171. }
  172. if (j > 0)
  173. {
  174. //node above
  175. float neighbour = verts[(i) * numVertsX + j - 1].z;
  176. sumNeighbours += neighbour;
  177. numNeighbours++;
  178. }
  179. if (j < numVertsX - 1)
  180. {
  181. //below
  182. float neighbour = verts[numVertsX + j + 1].z;
  183. sumNeighbours += neighbour;
  184. numNeighbours++;
  185. }
  186. if (i < (numVertsY - 1))
  187. {
  188. //right
  189. float neighbour = verts[(i + 1) * numVertsX + j].z;
  190. sumNeighbours += neighbour;
  191. numNeighbours++;
  192. }
  193. if (i > 0 && j < numVertsX - 1)
  194. {
  195. //left and below
  196. float neighbour = verts[(i - 1) * numVertsX + j + 1].z;
  197. sumNeighbours += neighbour;
  198. numNeighbours++;
  199. }
  200. if (j < (numVertsX - 1) && i < (numVertsY - 1))
  201. {
  202. //right and below
  203. float neighbour = verts[(i + 1) * numVertsX + j + 1].z;
  204. sumNeighbours += neighbour;
  205. numNeighbours++;
  206. }
  207. if (i < numVertsY - 1 && j > 0)
  208. {
  209. //right and above
  210. float neighbour = verts[(i + 1) * numVertsX + j - 1].z;
  211. sumNeighbours += neighbour;
  212. numNeighbours++;
  213. }
  214. Vector3 oldVert = verts[i * numVertsX + j];
  215. newVerts[i * numVertsX + j] = new Vector3(oldVert.x, oldVert.y, sumNeighbours / numNeighbours);
  216. }
  217. }
  218. return newVerts;
  219. }
  220. /*
  221. * creates the render view and sets the targets
  222. */
  223. void SetRenderView()
  224. {
  225. renderView = new udRenderTarget();
  226. if (!GlobalUDContext.isCreated)
  227. GlobalUDContext.Login();
  228. renderView.Create(GlobalUDContext.uContext, GlobalUDContext.renderer, (uint)widthPix, (uint)heightPix);
  229. depthBuffer = new float[widthPix * heightPix];
  230. colourBuffer = null;
  231. renderView.SetTargets(ref colourBuffer, 0, ref depthBuffer);
  232. }
  233. // Update is called once per frame
  234. void Update()
  235. {
  236. //code to follow a target around:
  237. //if we are following a target, we only update the corresponding mesh whne the object has moved a requisite distance,
  238. //this reduces the number of updates to the mesh required.
  239. Vector3 offset;
  240. if (!isStaticMesh && followTarget != null)
  241. {
  242. //check if the target has moved
  243. Vector3 newRot = transform.rotation.eulerAngles;
  244. if (lockRotationToBody.x)
  245. newRot.x = followTarget.transform.eulerAngles.x + this.bodyLockOffset.x;
  246. if (lockRotationToBody.y)
  247. newRot.y = followTarget.transform.eulerAngles.y + this.bodyLockOffset.y;
  248. if (lockRotationToBody.z)
  249. newRot.z = followTarget.transform.eulerAngles.z + this.bodyLockOffset.z;
  250. transform.eulerAngles = newRot;
  251. offset = Matrix4x4.Rotate(transform.rotation) * new Vector4(watcherPosition.x, watcherPosition.y, watcherPosition.z);
  252. bool thresholdTrigger = (this.transform.position - followTarget.transform.position).magnitude > followThreshold;
  253. if (!threshholdFollow || thresholdTrigger)
  254. {
  255. this.transform.position = followTarget.transform.position + offset;
  256. UpdateView();
  257. }
  258. }
  259. else if (!isStaticMesh)
  260. {
  261. //we update the mesh every frame
  262. UpdateView();
  263. }
  264. else {
  265. }
  266. }
  267. private void UpdateView()
  268. {
  269. if (renderView == null || renderView.pRenderView == IntPtr.Zero)
  270. SetRenderView();
  271. udRenderInstance[] modelArray = UDUtilities.getUDSInstances();
  272. Matrix4x4 watcherTrans = transform.localToWorldMatrix;
  273. double[] frontPlaneView = UDUtilities.GetUDMatrix(watcherTrans);
  274. renderView.SetMatrix(udSDK.udRenderTargetMatrix.Camera, frontPlaneView);
  275. Matrix4x4 projection = Matrix4x4.Ortho(-width / 2, width / 2, height / 2, -height / 2, zNear, zFar);
  276. renderView.SetMatrix(udSDK.udRenderTargetMatrix.Projection, UDUtilities.GetUDMatrix(projection));
  277. RenderOptions options = new RenderOptions();
  278. //we need the highest LOD if we are not updating the mesh every frame
  279. if(blockOnStream)
  280. options.options.flags = udRenderContextFlags.udRCF_BlockingStreaming;
  281. try
  282. {
  283. GlobalUDContext.renderer.Render(renderView, modelArray, modelArray.Length, options);
  284. }
  285. catch (Exception e){
  286. Debug.Log("Dropped frame: " + e.ToString());
  287. }
  288. MakeSheetMesh(width, height, (int)widthPix, (int)heightPix, depthBuffer);
  289. }
  290. public void OnDestroy()
  291. {
  292. Debug.Log("destroying plane");
  293. renderView.Destroy();
  294. }
  295. }