|
|
- using System;
- using Oculus.Avatar;
- using UnityEngine;
- using System.Runtime.InteropServices;
-
- public class OvrAvatarAssetMesh : OvrAvatarAsset
- {
- public Mesh mesh;
- private ovrAvatarSkinnedMeshPose skinnedBindPose;
- public string[] jointNames;
-
- public OvrAvatarAssetMesh(UInt64 _assetId, IntPtr asset, ovrAvatarAssetType meshType)
- {
- assetID = _assetId;
- mesh = new Mesh();
- mesh.name = "Procedural Geometry for asset " + _assetId;
-
- SetSkinnedBindPose(asset, meshType);
-
- long vertexCount = 0;
- IntPtr vertexBuffer = IntPtr.Zero;
- uint indexCount = 0;
- IntPtr indexBuffer = IntPtr.Zero;
-
- GetVertexAndIndexData(asset, meshType, out vertexCount, out vertexBuffer, out indexCount, out indexBuffer);
-
- AvatarLogger.Log("OvrAvatarAssetMesh: " + _assetId + " " + meshType.ToString() + " VertexCount:" + vertexCount);
-
- Vector3[] vertices = new Vector3[vertexCount];
- Vector3[] normals = new Vector3[vertexCount];
- Vector4[] tangents = new Vector4[vertexCount];
- Vector2[] uv = new Vector2[vertexCount];
- Color[] colors = new Color[vertexCount];
- BoneWeight[] boneWeights = new BoneWeight[vertexCount];
-
- long vertexBufferStart = vertexBuffer.ToInt64();
-
- // We have different underlying vertex types to unpack, so switch on mesh type.
- switch (meshType)
- {
- case ovrAvatarAssetType.Mesh:
- {
- long vertexSize = (long)Marshal.SizeOf(typeof(ovrAvatarMeshVertex));
-
- for (long i = 0; i < vertexCount; i++)
- {
- long offset = vertexSize * i;
-
- ovrAvatarMeshVertex vertex = (ovrAvatarMeshVertex)Marshal.PtrToStructure(new IntPtr(vertexBufferStart + offset), typeof(ovrAvatarMeshVertex));
- vertices[i] = new Vector3(vertex.x, vertex.y, -vertex.z);
- normals[i] = new Vector3(vertex.nx, vertex.ny, -vertex.nz);
- tangents[i] = new Vector4(vertex.tx, vertex.ty, -vertex.tz, vertex.tw);
- uv[i] = new Vector2(vertex.u, vertex.v);
- colors[i] = new Color(0, 0, 0, 1);
-
- boneWeights[i].boneIndex0 = vertex.blendIndices[0];
- boneWeights[i].boneIndex1 = vertex.blendIndices[1];
- boneWeights[i].boneIndex2 = vertex.blendIndices[2];
- boneWeights[i].boneIndex3 = vertex.blendIndices[3];
- boneWeights[i].weight0 = vertex.blendWeights[0];
- boneWeights[i].weight1 = vertex.blendWeights[1];
- boneWeights[i].weight2 = vertex.blendWeights[2];
- boneWeights[i].weight3 = vertex.blendWeights[3];
- }
- }
- break;
-
- case ovrAvatarAssetType.CombinedMesh:
- {
- long vertexSize = (long)Marshal.SizeOf(typeof(ovrAvatarMeshVertexV2));
-
- for (long i = 0; i < vertexCount; i++)
- {
- long offset = vertexSize * i;
-
- ovrAvatarMeshVertexV2 vertex = (ovrAvatarMeshVertexV2)Marshal.PtrToStructure(new IntPtr(vertexBufferStart + offset), typeof(ovrAvatarMeshVertexV2));
- vertices[i] = new Vector3(vertex.x, vertex.y, -vertex.z);
- normals[i] = new Vector3(vertex.nx, vertex.ny, -vertex.nz);
- tangents[i] = new Vector4(vertex.tx, vertex.ty, -vertex.tz, vertex.tw);
- uv[i] = new Vector2(vertex.u, vertex.v);
- colors[i] = new Color(vertex.r, vertex.g, vertex.b, vertex.a);
-
- boneWeights[i].boneIndex0 = vertex.blendIndices[0];
- boneWeights[i].boneIndex1 = vertex.blendIndices[1];
- boneWeights[i].boneIndex2 = vertex.blendIndices[2];
- boneWeights[i].boneIndex3 = vertex.blendIndices[3];
- boneWeights[i].weight0 = vertex.blendWeights[0];
- boneWeights[i].weight1 = vertex.blendWeights[1];
- boneWeights[i].weight2 = vertex.blendWeights[2];
- boneWeights[i].weight3 = vertex.blendWeights[3];
- }
- }
- break;
- default:
- throw new Exception("Bad Mesh Asset Type");
- }
-
- mesh.vertices = vertices;
- mesh.normals = normals;
- mesh.uv = uv;
- mesh.tangents = tangents;
- mesh.boneWeights = boneWeights;
- mesh.colors = colors;
-
- LoadBlendShapes(asset, vertexCount);
- LoadSubmeshes(asset, indexBuffer, indexCount);
-
- UInt32 jointCount = skinnedBindPose.jointCount;
- jointNames = new string[jointCount];
- for (UInt32 i = 0; i < jointCount; i++)
- {
- jointNames[i] = Marshal.PtrToStringAnsi(skinnedBindPose.jointNames[i]);
- }
- }
-
- private void LoadSubmeshes(IntPtr asset, IntPtr indexBufferPtr, ulong indexCount)
- {
- UInt32 subMeshCount = CAPI.ovrAvatarAsset_GetSubmeshCount(asset);
-
- AvatarLogger.Log("LoadSubmeshes: " + subMeshCount);
-
- Int16[] indices = new Int16[indexCount];
- Marshal.Copy(indexBufferPtr, indices, 0, (int)indexCount);
-
- mesh.subMeshCount = (int)subMeshCount;
- uint accumedOffset = 0;
- for (UInt32 index = 0; index < subMeshCount; index++)
- {
- var submeshIndexCount = CAPI.ovrAvatarAsset_GetSubmeshLastIndex(asset, index);
- var currSpan = submeshIndexCount - accumedOffset;
-
- Int32[] triangles = new Int32[currSpan];
-
- int triangleOffset = 0;
- for (ulong i = accumedOffset; i < submeshIndexCount; i += 3)
- {
- // NOTE: We are changing the order of each triangle to match unity expectations vs pipeline.
- triangles[triangleOffset + 2] = (Int32)indices[i];
- triangles[triangleOffset + 1] = (Int32)indices[i + 1];
- triangles[triangleOffset] = (Int32)indices[i + 2];
-
- triangleOffset += 3;
- }
-
- accumedOffset += currSpan;
-
- mesh.SetIndices(triangles, MeshTopology.Triangles, (int)index);
- }
- }
-
- private void LoadBlendShapes(IntPtr asset, long vertexCount)
- {
- UInt32 blendShapeCount = CAPI.ovrAvatarAsset_GetMeshBlendShapeCount(asset);
- IntPtr blendShapeVerts = CAPI.ovrAvatarAsset_GetMeshBlendShapeVertices(asset);
-
- AvatarLogger.Log("LoadBlendShapes: " + blendShapeCount);
-
- if (blendShapeVerts != IntPtr.Zero)
- {
- long offset = 0;
- long blendVertexSize = (long)Marshal.SizeOf(typeof(ovrAvatarBlendVertex));
- long blendVertexBufferStart = blendShapeVerts.ToInt64();
-
- for (UInt32 blendIndex = 0; blendIndex < blendShapeCount; blendIndex++)
- {
- Vector3[] blendVerts = new Vector3[vertexCount];
- Vector3[] blendNormals = new Vector3[vertexCount];
- Vector3[] blendTangents = new Vector3[vertexCount];
-
- for (long i = 0; i < vertexCount; i++)
- {
- ovrAvatarBlendVertex vertex = (ovrAvatarBlendVertex)Marshal.PtrToStructure(new IntPtr(blendVertexBufferStart + offset), typeof(ovrAvatarBlendVertex));
- blendVerts[i] = new Vector3(vertex.x, vertex.y, -vertex.z);
- blendNormals[i] = new Vector3(vertex.nx, vertex.ny, -vertex.nz);
- blendTangents[i] = new Vector4(vertex.tx, vertex.ty, -vertex.tz);
-
- offset += blendVertexSize;
- }
-
- IntPtr namePtr = CAPI.ovrAvatarAsset_GetMeshBlendShapeName(asset, blendIndex);
- string name = Marshal.PtrToStringAnsi(namePtr);
- const float frameWeight = 100f;
- mesh.AddBlendShapeFrame(name, frameWeight, blendVerts, blendNormals, blendTangents);
- }
- }
- }
-
- private void SetSkinnedBindPose(IntPtr asset, ovrAvatarAssetType meshType)
- {
- switch (meshType)
- {
- case ovrAvatarAssetType.Mesh:
- skinnedBindPose = CAPI.ovrAvatarAsset_GetMeshData(asset).skinnedBindPose;
- break;
- case ovrAvatarAssetType.CombinedMesh:
- skinnedBindPose = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).skinnedBindPose;
- break;
- default:
- break;
-
- }
- }
-
- private void GetVertexAndIndexData(
- IntPtr asset,
- ovrAvatarAssetType meshType,
- out long vertexCount,
- out IntPtr vertexBuffer,
- out uint indexCount,
- out IntPtr indexBuffer)
- {
- vertexCount = 0;
- vertexBuffer = IntPtr.Zero;
- indexCount = 0;
- indexBuffer = IntPtr.Zero;
-
- switch (meshType)
- {
- case ovrAvatarAssetType.Mesh:
- vertexCount = CAPI.ovrAvatarAsset_GetMeshData(asset).vertexCount;
- vertexBuffer = CAPI.ovrAvatarAsset_GetMeshData(asset).vertexBuffer;
- indexCount = CAPI.ovrAvatarAsset_GetMeshData(asset).indexCount;
- indexBuffer = CAPI.ovrAvatarAsset_GetMeshData(asset).indexBuffer;
- break;
- case ovrAvatarAssetType.CombinedMesh:
- vertexCount = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).vertexCount;
- vertexBuffer = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).vertexBuffer;
- indexCount = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).indexCount;
- indexBuffer = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset).indexBuffer;
- break;
- default:
- break;
- }
- }
-
- public SkinnedMeshRenderer CreateSkinnedMeshRendererOnObject(GameObject target)
- {
- SkinnedMeshRenderer skinnedMeshRenderer = target.AddComponent<SkinnedMeshRenderer>();
- skinnedMeshRenderer.sharedMesh = mesh;
- mesh.name = "AvatarMesh_" + assetID;
- UInt32 jointCount = skinnedBindPose.jointCount;
- GameObject[] bones = new GameObject[jointCount];
- Transform[] boneTransforms = new Transform[jointCount];
- Matrix4x4[] bindPoses = new Matrix4x4[jointCount];
- for (UInt32 i = 0; i < jointCount; i++)
- {
- bones[i] = new GameObject();
- boneTransforms[i] = bones[i].transform;
- bones[i].name = jointNames[i];
- int parentIndex = skinnedBindPose.jointParents[i];
- if (parentIndex == -1)
- {
- bones[i].transform.parent = skinnedMeshRenderer.transform;
- skinnedMeshRenderer.rootBone = bones[i].transform;
- }
- else
- {
- bones[i].transform.parent = bones[parentIndex].transform;
- }
-
- // Set the position relative to the parent
- Vector3 position = skinnedBindPose.jointTransform[i].position;
- position.z = -position.z;
- bones[i].transform.localPosition = position;
-
- Quaternion orientation = skinnedBindPose.jointTransform[i].orientation;
- orientation.x = -orientation.x;
- orientation.y = -orientation.y;
- bones[i].transform.localRotation = orientation;
-
- bones[i].transform.localScale = skinnedBindPose.jointTransform[i].scale;
-
- bindPoses[i] = bones[i].transform.worldToLocalMatrix * skinnedMeshRenderer.transform.localToWorldMatrix;
- }
- skinnedMeshRenderer.bones = boneTransforms;
- mesh.bindposes = bindPoses;
- return skinnedMeshRenderer;
- }
- }
|