Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

279 lines
12 KiB

  1. using System;
  2. using Oculus.Avatar;
  3. using UnityEngine;
  4. using System.Runtime.InteropServices;
  5. public class OvrAvatarAssetMesh : OvrAvatarAsset
  6. {
  7. public Mesh mesh;
  8. private ovrAvatarSkinnedMeshPose skinnedBindPose;
  9. public string[] jointNames;
  10. public OvrAvatarAssetMesh(UInt64 _assetId, IntPtr asset, ovrAvatarAssetType meshType)
  11. {
  12. assetID = _assetId;
  13. mesh = new Mesh();
  14. mesh.name = "Procedural Geometry for asset " + _assetId;
  15. SetSkinnedBindPose(asset, meshType);
  16. long vertexCount = 0;
  17. IntPtr vertexBuffer = IntPtr.Zero;
  18. uint indexCount = 0;
  19. IntPtr indexBuffer = IntPtr.Zero;
  20. GetVertexAndIndexData(asset, meshType, out vertexCount, out vertexBuffer, out indexCount, out indexBuffer);
  21. AvatarLogger.Log("OvrAvatarAssetMesh: " + _assetId + " " + meshType.ToString() + " VertexCount:" + vertexCount);
  22. Vector3[] vertices = new Vector3[vertexCount];
  23. Vector3[] normals = new Vector3[vertexCount];
  24. Vector4[] tangents = new Vector4[vertexCount];
  25. Vector2[] uv = new Vector2[vertexCount];
  26. Color[] colors = new Color[vertexCount];
  27. BoneWeight[] boneWeights = new BoneWeight[vertexCount];
  28. long vertexBufferStart = vertexBuffer.ToInt64();
  29. // We have different underlying vertex types to unpack, so switch on mesh type.
  30. switch (meshType)
  31. {
  32. case ovrAvatarAssetType.Mesh:
  33. {
  34. long vertexSize = (long)Marshal.SizeOf(typeof(ovrAvatarMeshVertex));
  35. for (long i = 0; i < vertexCount; i++)
  36. {
  37. long offset = vertexSize * i;
  38. ovrAvatarMeshVertex vertex = (ovrAvatarMeshVertex)Marshal.PtrToStructure(new IntPtr(vertexBufferStart + offset), typeof(ovrAvatarMeshVertex));
  39. vertices[i] = new Vector3(vertex.x, vertex.y, -vertex.z);
  40. normals[i] = new Vector3(vertex.nx, vertex.ny, -vertex.nz);
  41. tangents[i] = new Vector4(vertex.tx, vertex.ty, -vertex.tz, vertex.tw);
  42. uv[i] = new Vector2(vertex.u, vertex.v);
  43. colors[i] = new Color(0, 0, 0, 1);
  44. boneWeights[i].boneIndex0 = vertex.blendIndices[0];
  45. boneWeights[i].boneIndex1 = vertex.blendIndices[1];
  46. boneWeights[i].boneIndex2 = vertex.blendIndices[2];
  47. boneWeights[i].boneIndex3 = vertex.blendIndices[3];
  48. boneWeights[i].weight0 = vertex.blendWeights[0];
  49. boneWeights[i].weight1 = vertex.blendWeights[1];
  50. boneWeights[i].weight2 = vertex.blendWeights[2];
  51. boneWeights[i].weight3 = vertex.blendWeights[3];
  52. }
  53. }
  54. break;
  55. case ovrAvatarAssetType.CombinedMesh:
  56. {
  57. long vertexSize = (long)Marshal.SizeOf(typeof(ovrAvatarMeshVertexV2));
  58. for (long i = 0; i < vertexCount; i++)
  59. {
  60. long offset = vertexSize * i;
  61. ovrAvatarMeshVertexV2 vertex = (ovrAvatarMeshVertexV2)Marshal.PtrToStructure(new IntPtr(vertexBufferStart + offset), typeof(ovrAvatarMeshVertexV2));
  62. vertices[i] = new Vector3(vertex.x, vertex.y, -vertex.z);
  63. normals[i] = new Vector3(vertex.nx, vertex.ny, -vertex.nz);
  64. tangents[i] = new Vector4(vertex.tx, vertex.ty, -vertex.tz, vertex.tw);
  65. uv[i] = new Vector2(vertex.u, vertex.v);
  66. colors[i] = new Color(vertex.r, vertex.g, vertex.b, vertex.a);
  67. boneWeights[i].boneIndex0 = vertex.blendIndices[0];
  68. boneWeights[i].boneIndex1 = vertex.blendIndices[1];
  69. boneWeights[i].boneIndex2 = vertex.blendIndices[2];
  70. boneWeights[i].boneIndex3 = vertex.blendIndices[3];
  71. boneWeights[i].weight0 = vertex.blendWeights[0];
  72. boneWeights[i].weight1 = vertex.blendWeights[1];
  73. boneWeights[i].weight2 = vertex.blendWeights[2];
  74. boneWeights[i].weight3 = vertex.blendWeights[3];
  75. }
  76. }
  77. break;
  78. default:
  79. throw new Exception("Bad Mesh Asset Type");
  80. }
  81. mesh.vertices = vertices;
  82. mesh.normals = normals;
  83. mesh.uv = uv;
  84. mesh.tangents = tangents;
  85. mesh.boneWeights = boneWeights;
  86. mesh.colors = colors;
  87. LoadBlendShapes(asset, vertexCount);
  88. LoadSubmeshes(asset, indexBuffer, indexCount);
  89. UInt32 jointCount = skinnedBindPose.jointCount;
  90. jointNames = new string[jointCount];
  91. for (UInt32 i = 0; i < jointCount; i++)
  92. {
  93. jointNames[i] = Marshal.PtrToStringAnsi(skinnedBindPose.jointNames[i]);
  94. }
  95. }
  96. private void LoadSubmeshes(IntPtr asset, IntPtr indexBufferPtr, ulong indexCount)
  97. {
  98. UInt32 subMeshCount = CAPI.ovrAvatarAsset_GetSubmeshCount(asset);
  99. AvatarLogger.Log("LoadSubmeshes: " + subMeshCount);
  100. Int16[] indices = new Int16[indexCount];
  101. Marshal.Copy(indexBufferPtr, indices, 0, (int)indexCount);
  102. mesh.subMeshCount = (int)subMeshCount;
  103. uint accumedOffset = 0;
  104. for (UInt32 index = 0; index < subMeshCount; index++)
  105. {
  106. var submeshIndexCount = CAPI.ovrAvatarAsset_GetSubmeshLastIndex(asset, index);
  107. var currSpan = submeshIndexCount - accumedOffset;
  108. Int32[] triangles = new Int32[currSpan];
  109. int triangleOffset = 0;
  110. for (ulong i = accumedOffset; i < submeshIndexCount; i += 3)
  111. {
  112. // NOTE: We are changing the order of each triangle to match unity expectations vs pipeline.
  113. triangles[triangleOffset + 2] = (Int32)indices[i];
  114. triangles[triangleOffset + 1] = (Int32)indices[i + 1];
  115. triangles[triangleOffset] = (Int32)indices[i + 2];
  116. triangleOffset += 3;
  117. }
  118. accumedOffset += currSpan;
  119. mesh.SetIndices(triangles, MeshTopology.Triangles, (int)index);
  120. }
  121. }
  122. private void LoadBlendShapes(IntPtr asset, long vertexCount)
  123. {
  124. UInt32 blendShapeCount = CAPI.ovrAvatarAsset_GetMeshBlendShapeCount(asset);
  125. IntPtr blendShapeVerts = CAPI.ovrAvatarAsset_GetMeshBlendShapeVertices(asset);
  126. AvatarLogger.Log("LoadBlendShapes: " + blendShapeCount);
  127. if (blendShapeVerts != IntPtr.Zero)
  128. {
  129. long offset = 0;
  130. long blendVertexSize = (long)Marshal.SizeOf(typeof(ovrAvatarBlendVertex));
  131. long blendVertexBufferStart = blendShapeVerts.ToInt64();
  132. for (UInt32 blendIndex = 0; blendIndex < blendShapeCount; blendIndex++)
  133. {
  134. Vector3[] blendVerts = new Vector3[vertexCount];
  135. Vector3[] blendNormals = new Vector3[vertexCount];
  136. Vector3[] blendTangents = new Vector3[vertexCount];
  137. for (long i = 0; i < vertexCount; i++)
  138. {
  139. ovrAvatarBlendVertex vertex = (ovrAvatarBlendVertex)Marshal.PtrToStructure(new IntPtr(blendVertexBufferStart + offset), typeof(ovrAvatarBlendVertex));
  140. blendVerts[i] = new Vector3(vertex.x, vertex.y, -vertex.z);
  141. blendNormals[i] = new Vector3(vertex.nx, vertex.ny, -vertex.nz);
  142. blendTangents[i] = new Vector4(vertex.tx, vertex.ty, -vertex.tz);
  143. offset += blendVertexSize;
  144. }
  145. IntPtr namePtr = CAPI.ovrAvatarAsset_GetMeshBlendShapeName(asset, blendIndex);
  146. string name = Marshal.PtrToStringAnsi(namePtr);
  147. const float frameWeight = 100f;
  148. mesh.AddBlendShapeFrame(name, frameWeight, blendVerts, blendNormals, blendTangents);
  149. }
  150. }
  151. }
  152. private void SetSkinnedBindPose(IntPtr asset, ovrAvatarAssetType meshType)
  153. {
  154. switch (meshType)
  155. {
  156. case ovrAvatarAssetType.Mesh:
  157. skinnedBindPose = CAPI.ovrAvatarAsset_GetMeshData(asset).skinnedBindPose;
  158. break;
  159. case ovrAvatarAssetType.CombinedMesh:
  160. skinnedBindPose = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).skinnedBindPose;
  161. break;
  162. default:
  163. break;
  164. }
  165. }
  166. private void GetVertexAndIndexData(
  167. IntPtr asset,
  168. ovrAvatarAssetType meshType,
  169. out long vertexCount,
  170. out IntPtr vertexBuffer,
  171. out uint indexCount,
  172. out IntPtr indexBuffer)
  173. {
  174. vertexCount = 0;
  175. vertexBuffer = IntPtr.Zero;
  176. indexCount = 0;
  177. indexBuffer = IntPtr.Zero;
  178. switch (meshType)
  179. {
  180. case ovrAvatarAssetType.Mesh:
  181. vertexCount = CAPI.ovrAvatarAsset_GetMeshData(asset).vertexCount;
  182. vertexBuffer = CAPI.ovrAvatarAsset_GetMeshData(asset).vertexBuffer;
  183. indexCount = CAPI.ovrAvatarAsset_GetMeshData(asset).indexCount;
  184. indexBuffer = CAPI.ovrAvatarAsset_GetMeshData(asset).indexBuffer;
  185. break;
  186. case ovrAvatarAssetType.CombinedMesh:
  187. vertexCount = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).vertexCount;
  188. vertexBuffer = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).vertexBuffer;
  189. indexCount = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).indexCount;
  190. indexBuffer = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).indexBuffer;
  191. break;
  192. default:
  193. break;
  194. }
  195. }
  196. public SkinnedMeshRenderer CreateSkinnedMeshRendererOnObject(GameObject target)
  197. {
  198. SkinnedMeshRenderer skinnedMeshRenderer = target.AddComponent<SkinnedMeshRenderer>();
  199. skinnedMeshRenderer.sharedMesh = mesh;
  200. mesh.name = "AvatarMesh_" + assetID;
  201. UInt32 jointCount = skinnedBindPose.jointCount;
  202. GameObject[] bones = new GameObject[jointCount];
  203. Transform[] boneTransforms = new Transform[jointCount];
  204. Matrix4x4[] bindPoses = new Matrix4x4[jointCount];
  205. for (UInt32 i = 0; i < jointCount; i++)
  206. {
  207. bones[i] = new GameObject();
  208. boneTransforms[i] = bones[i].transform;
  209. bones[i].name = jointNames[i];
  210. int parentIndex = skinnedBindPose.jointParents[i];
  211. if (parentIndex == -1)
  212. {
  213. bones[i].transform.parent = skinnedMeshRenderer.transform;
  214. skinnedMeshRenderer.rootBone = bones[i].transform;
  215. }
  216. else
  217. {
  218. bones[i].transform.parent = bones[parentIndex].transform;
  219. }
  220. // Set the position relative to the parent
  221. Vector3 position = skinnedBindPose.jointTransform[i].position;
  222. position.z = -position.z;
  223. bones[i].transform.localPosition = position;
  224. Quaternion orientation = skinnedBindPose.jointTransform[i].orientation;
  225. orientation.x = -orientation.x;
  226. orientation.y = -orientation.y;
  227. bones[i].transform.localRotation = orientation;
  228. bones[i].transform.localScale = skinnedBindPose.jointTransform[i].scale;
  229. bindPoses[i] = bones[i].transform.worldToLocalMatrix * skinnedMeshRenderer.transform.localToWorldMatrix;
  230. }
  231. skinnedMeshRenderer.bones = boneTransforms;
  232. mesh.bindposes = bindPoses;
  233. return skinnedMeshRenderer;
  234. }
  235. }