diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index eeb82f652..dd368215e 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -177,9 +177,9 @@ namespace UniGLTF var index = i; using (MeasureTime("ReadMesh")) { - var x = await awaitCaller.Run(() => meshImporter.ReadMesh(Data, index, inverter)); - var y = await BuildMeshAsync(awaitCaller, MeasureTime, x, index); - Meshes.Add(y); + var meshContext = await awaitCaller.Run(() => meshImporter.ReadMesh(Data, index, inverter)); + var meshWithMaterials = await BuildMeshAsync(awaitCaller, MeasureTime, meshContext, index); + Meshes.Add(meshWithMaterials); } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs index e223014e7..00190cf58 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshContext.cs @@ -2,42 +2,50 @@ using System; using System.Collections.Generic; using System.Linq; using UnityEngine; +using UnityEngine.Profiling; +using UnityEngine.Rendering; namespace UniGLTF { - public class MeshContext + internal class MeshContext { - private readonly List _positions = new List(); - private readonly List _normals = new List(); - [Obsolete] private readonly List _tangents = new List(); - private readonly List _uv = new List(); - private readonly List _uv2 = new List(); - private readonly List _colors = new List(); - private readonly List _boneWeights = new List(); - private readonly List _subMeshes = new List(); + private readonly List _vertices = new List(); + private readonly List _indices = new List(); + private readonly List _subMeshes = new List(); private readonly List _materialIndices = new List(); private readonly List _blendShapes = new List(); - public IReadOnlyList Positions => _positions; - public IReadOnlyList Normals => _normals; - - [Obsolete] public IReadOnlyList Tangetns => _tangents; - - public IReadOnlyList UV => _uv; - - public IReadOnlyList UV2 => _uv2; - public IReadOnlyList Colors => _colors; - - public IReadOnlyList BoneWeights => _boneWeights; - - public IReadOnlyList SubMeshes => _subMeshes; - public IReadOnlyList MaterialIndices => _materialIndices; - public IReadOnlyList BlendShapes => _blendShapes; + public bool HasNormal { get; private set; } = true; + public string Name { get; } + /// + /// 頂点情報をMeshに対して送る + /// + /// + public void UploadMeshVertices(Mesh mesh) + { + mesh.SetVertexBufferParams(_vertices.Count, MeshVertex.GetVertexAttributeDescriptor()); + mesh.SetVertexBufferData(_vertices, 0, 0, _vertices.Count); + } + /// + /// インデックス情報をMeshに対して送る + /// + /// + public void UploadMeshIndices(Mesh mesh) + { + mesh.SetIndexBufferParams(_indices.Count, IndexFormat.UInt32); + mesh.SetIndexBufferData(_indices, 0, 0, _indices.Count); + mesh.subMeshCount = _subMeshes.Count; + for (var i = 0; i < _subMeshes.Count; i++) + { + mesh.SetSubMesh(i, _subMeshes[i]); + } + } + private BlendShape GetOrCreateBlendShape(int i) { if (i < _blendShapes.Count && _blendShapes[i] != null) @@ -62,41 +70,23 @@ namespace UniGLTF name = $"UniGLTF import#{meshIndex}"; } - this.Name = name; + Name = name; } - /// - /// Fill list with 0s with the specified length - /// - /// - /// - /// - private static void FillZero(ICollection list, int fillLength) + private static (float x, float y, float z, float w) NormalizeBoneWeight( + (float x, float y, float z, float w) src) { - if (list.Count > fillLength) - { - throw new Exception("Impossible"); - } - - while (list.Count < fillLength) - { - list.Add(default); - } - } - - private static BoneWeight NormalizeBoneWeight(BoneWeight src) - { - var sum = src.weight0 + src.weight1 + src.weight2 + src.weight3; + var sum = src.x + src.y + src.z + src.w; if (sum == 0) { return src; } var f = 1.0f / sum; - src.weight0 *= f; - src.weight1 *= f; - src.weight2 *= f; - src.weight3 *= f; + src.x *= f; + src.y *= f; + src.z *= f; + src.w *= f; return src; } @@ -111,127 +101,72 @@ namespace UniGLTF /// public void ImportMeshIndependentVertexBuffer(GltfData data, glTFMesh gltfMesh, IAxisInverter inverter) { - foreach (var prim in gltfMesh.primitives) + foreach (var primitives in gltfMesh.primitives) { - var indexOffset = _positions.Count; - var indexBuffer = prim.indices; + var vertexOffset = _vertices.Count; + var indexBufferCount = primitives.indices; // position は必ずある - var positions = data.GetArrayFromAccessor(prim.attributes.POSITION); - _positions.AddRange(positions.Select(inverter.InvertVector3)); - var fillLength = _positions.Count; + var positions = primitives.GetPositions(data); + var normals = primitives.GetNormals(data, positions.Length); + var texCoords0 = primitives.GetTexCoords0(data, positions.Length); + var texCoords1 = primitives.GetTexCoords1(data, positions.Length); + var colors = primitives.GetColors(data, positions.Length); + var jointsGetter = primitives.GetJoints(data, positions.Length); + var weightsGetter = primitives.GetWeights(data, positions.Length); - // normal - if (prim.attributes.NORMAL != -1) + CheckAttributeUsages(primitives); + + for (var i = 0; i < positions.Length; ++i) { - var normals = data.GetArrayFromAccessor(prim.attributes.NORMAL); - if (normals.Length != positions.Length) - { - throw new Exception("different length"); - } + var position = inverter.InvertVector3(positions[i]); + var normal = normals != null ? inverter.InvertVector3(normals[i]) : Vector3.zero; - _normals.AddRange(normals.Select(inverter.InvertVector3)); - FillZero(_normals, fillLength); - } - - // uv - if (prim.attributes.TEXCOORD_0 != -1) - { - var uvs = data.GetArrayFromAccessor(prim.attributes.TEXCOORD_0); - if (uvs.Length != positions.Length) - { - throw new Exception("different length"); - } - - if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16)) + var texCoord0 = Vector2.zero; + if (texCoords0 != null) { + if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16)) + { #pragma warning disable 0612 - // backward compatibility - _uv.AddRange(uvs.Select(x => x.ReverseY())); - FillZero(_uv, fillLength); + // backward compatibility + texCoord0 = texCoords0[i].ReverseY(); #pragma warning restore 0612 - } - else - { - _uv.AddRange(uvs.Select(x => x.ReverseUV())); - FillZero(_uv, fillLength); - } - } - - // uv2 - if (prim.attributes.TEXCOORD_1 != -1) - { - var uvs = data.GetArrayFromAccessor(prim.attributes.TEXCOORD_1); - if (uvs.Length != positions.Length) - { - throw new Exception("different length"); + } + else + { + texCoord0 = texCoords0[i].ReverseUV(); + } } - _uv2.AddRange(uvs.Select(x => x.ReverseUV())); - FillZero(_uv2, fillLength); - } + var texCoord1 = texCoords1 != null ? texCoords1[i].ReverseUV() : Vector2.zero; + var joints = jointsGetter?.Invoke(i) ?? (0, 0, 0, 0); + var weights = weightsGetter != null ? NormalizeBoneWeight(weightsGetter(i)) : (0, 0, 0, 0); - // color - if (prim.attributes.COLOR_0 != -1) - { - var colors = data.GetArrayFromAccessor(prim.attributes.COLOR_0); - if (colors.Length != positions.Length) - { - throw new Exception("different length"); - } - - _colors.AddRange(colors); - FillZero(_colors, fillLength); - } - - // skin - if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) - { - var (joints0, jointsLength) = JointsAccessor.GetAccessor(data, prim.attributes.JOINTS_0); - var (weights0, weightsLength) = WeightsAccessor.GetAccessor(data, prim.attributes.WEIGHTS_0); - if (jointsLength != positions.Length) - { - throw new Exception("different length"); - } - - if (weightsLength != positions.Length) - { - throw new Exception("different length"); - } - - for (var j = 0; j < jointsLength; ++j) - { - var bw = new BoneWeight(); - - var joints = joints0(j); - var weights = weights0(j); - - bw.boneIndex0 = joints.x; - bw.weight0 = weights.x; - - bw.boneIndex1 = joints.y; - bw.weight1 = weights.y; - - bw.boneIndex2 = joints.z; - bw.weight2 = weights.z; - - bw.boneIndex3 = joints.w; - bw.weight3 = weights.w; - - bw = NormalizeBoneWeight(bw); - - _boneWeights.Add(bw); - } - - FillZero(_boneWeights, fillLength); + var color = colors[i]; + _vertices.Add( + new MeshVertex( + position, + normal, + texCoord0, + texCoord1, + color, + joints.x, + joints.y, + joints.z, + joints.w, + weights.x, + weights.y, + weights.z, + weights.w + )); } // blendshape - if (prim.targets != null && prim.targets.Count > 0) + if (primitives.targets != null && primitives.targets.Count > 0) { - for (var i = 0; i < prim.targets.Count; ++i) + for (var i = 0; i < primitives.targets.Count; ++i) { - var primTarget = prim.targets[i]; + var primTarget = primitives.targets[i]; var blendShape = GetOrCreateBlendShape(i); if (primTarget.POSITION != -1) { @@ -242,7 +177,6 @@ namespace UniGLTF } blendShape.Positions.AddRange(array.Select(inverter.InvertVector3).ToArray()); - FillZero(blendShape.Positions, fillLength); } if (primTarget.NORMAL != -1) @@ -254,7 +188,6 @@ namespace UniGLTF } blendShape.Normals.AddRange(array.Select(inverter.InvertVector3).ToArray()); - FillZero(blendShape.Normals, fillLength); } if (primTarget.TANGENT != -1) @@ -266,29 +199,38 @@ namespace UniGLTF } blendShape.Tangents.AddRange(array.Select(inverter.InvertVector3).ToArray()); - FillZero(blendShape.Tangents, fillLength); } } } - var indices = - (indexBuffer >= 0) - ? data.GetIndices(indexBuffer) - : TriangleUtil.FlipTriangle(Enumerable.Range(0, _positions.Count)) - .ToArray() // without index array - ; - for (var i = 0; i < indices.Length; ++i) + if (indexBufferCount >= 0) { - indices[i] += indexOffset; + var indexOffset = _indices.Count; + var dataIndices = data.GetIndices(indexBufferCount); + _indices.AddRange(dataIndices.Select(index => index + vertexOffset)); + _subMeshes.Add(new SubMeshDescriptor(indexOffset, dataIndices.Length)); + } + else + { + var indexOffset = _indices.Count; + _indices.AddRange(TriangleUtil.FlipTriangle(Enumerable.Range(0, _vertices.Count)).Select(index => index + vertexOffset)); + _subMeshes.Add(new SubMeshDescriptor(indexOffset, _vertices.Count)); } - _subMeshes.Add(indices); - // material - _materialIndices.Add(prim.material); + _materialIndices.Add(primitives.material); } } + /// + /// 各種頂点属性が使われているかどうかをチェックし、使われていなかったらフラグを切る + /// MEMO: O(1)で検知する手段がありそう + /// + private void CheckAttributeUsages(glTFPrimitives primitives) + { + if (!primitives.HasNormal()) HasNormal = false; + } + /// /// /// 各primitiveが同じ attribute を共有している場合専用のローダー。 @@ -301,116 +243,67 @@ namespace UniGLTF { { // 同じVertexBufferを共有しているので先頭のモノを使う - var prim = gltfMesh.primitives.First(); - _positions.AddRange(data.GetArrayFromAccessor(prim.attributes.POSITION) - .SelectInplace(inverter.InvertVector3)); + var primitives = gltfMesh.primitives.First(); - // normal - if (prim.attributes.NORMAL != -1) + var positions = primitives.GetPositions(data); + var normals = primitives.GetNormals(data, positions.Length); + var texCoords0 = primitives.GetTexCoords0(data, positions.Length); + var texCoords1 = primitives.GetTexCoords1(data, positions.Length); + var colors = primitives.GetColors(data, positions.Length); + var jointsGetter = primitives.GetJoints(data, positions.Length); + var weightsGetter = primitives.GetWeights(data, positions.Length); + + CheckAttributeUsages(primitives); + + for (var i = 0; i < positions.Length; ++i) { - _normals.AddRange(data.GetArrayFromAccessor(prim.attributes.NORMAL) - .SelectInplace(inverter.InvertVector3)); - } - -#if false - // tangent - if (prim.attributes.TANGENT != -1) + var position = inverter.InvertVector3(positions[i]); + var normal = normals != null ? inverter.InvertVector3(normals[i]) : Vector3.zero; + var texCoord0 = Vector2.zero; + if (texCoords0 != null) { - tangents.AddRange(gltf.GetArrayFromAccessor(prim.attributes.TANGENT).SelectInplace(inverter.InvertVector4)); - } -#endif - - // uv - if (prim.attributes.TEXCOORD_0 != -1) - { - if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16)) - { -#pragma warning disable 0612 - // backward compatibility - _uv.AddRange(data.GetArrayFromAccessor(prim.attributes.TEXCOORD_0) - .SelectInplace(x => x.ReverseY())); -#pragma warning restore 0612 - } - else - { - _uv.AddRange(data.GetArrayFromAccessor(prim.attributes.TEXCOORD_0) - .SelectInplace(x => x.ReverseUV())); - } - } - - // uv2 - if (prim.attributes.TEXCOORD_1 != -1) - { - _uv2.AddRange(data.GetArrayFromAccessor(prim.attributes.TEXCOORD_1) - .SelectInplace(x => x.ReverseUV())); - } - - // color - if (prim.attributes.COLOR_0 != -1) - { - switch (data.GLTF.accessors[prim.attributes.COLOR_0].TypeCount) - { - case 3: + if (data.GLTF.IsGeneratedUniGLTFAndOlder(1, 16)) { - var vec3Color = data.GetArrayFromAccessor(prim.attributes.COLOR_0); - _colors.AddRange(new Color[vec3Color.Length]); - - for (var i = 0; i < vec3Color.Length; i++) - { - var color = vec3Color[i]; - _colors[i] = new Color(color.x, color.y, color.z); - } - - break; +#pragma warning disable 0612 + texCoord0 = texCoords0[i].ReverseY(); +#pragma warning restore 0612 + } + else + { + texCoord0 = texCoords0[i].ReverseUV(); } - case 4: - _colors.AddRange(data.GetArrayFromAccessor(prim.attributes.COLOR_0)); - break; - default: - throw new NotImplementedException( - $"unknown color type {data.GLTF.accessors[prim.attributes.COLOR_0].type}"); } - } - // skin - if (prim.attributes.JOINTS_0 != -1 && prim.attributes.WEIGHTS_0 != -1) - { - var (joints0, jointsLength) = JointsAccessor.GetAccessor(data, prim.attributes.JOINTS_0); - var (weights0, weightsLength) = WeightsAccessor.GetAccessor(data, prim.attributes.WEIGHTS_0); + var texCoord1 = texCoords1 != null ? texCoords1[i].ReverseUV() : Vector2.zero; + var color = colors != null ? colors[i] : Color.black; + var joints = jointsGetter?.Invoke(i) ?? (0, 0, 0, 0); + var weights = weightsGetter != null ? NormalizeBoneWeight(weightsGetter(i)) : (0, 0, 0, 0); - for (var j = 0; j < jointsLength; ++j) - { - var bw = new BoneWeight(); - - var joints = joints0(j); - var weights = weights0(j); - - bw.boneIndex0 = joints.x; - bw.weight0 = weights.x; - - bw.boneIndex1 = joints.y; - bw.weight1 = weights.y; - - bw.boneIndex2 = joints.z; - bw.weight2 = weights.z; - - bw.boneIndex3 = joints.w; - bw.weight3 = weights.w; - - bw = NormalizeBoneWeight(bw); - - _boneWeights.Add(bw); - } + _vertices.Add(new MeshVertex( + position, + normal, + texCoord0, + texCoord1, + color, + joints.x, + joints.y, + joints.z, + joints.w, + weights.x, + weights.y, + weights.z, + weights.w + )); } // blendshape - if (prim.targets != null && prim.targets.Count > 0) + if (primitives.targets != null && primitives.targets.Count > 0) { - _blendShapes.AddRange(prim.targets.Select((x, i) => new BlendShape(i.ToString()))); - for (int i = 0; i < prim.targets.Count; ++i) + _blendShapes.AddRange(primitives.targets.Select((x, i) => new BlendShape(i.ToString()))); + for (int i = 0; i < primitives.targets.Count; ++i) { //var name = string.Format("target{0}", i++); - var primTarget = prim.targets[i]; + var primTarget = primitives.targets[i]; var blendShape = _blendShapes[i]; if (primTarget.POSITION != -1) @@ -434,20 +327,24 @@ namespace UniGLTF } } - foreach (var prim in gltfMesh.primitives) + foreach (var primitive in gltfMesh.primitives) { - if (prim.indices == -1) + if (primitive.indices == -1) { - _subMeshes.Add(TriangleUtil.FlipTriangle(Enumerable.Range(0, _positions.Count)).ToArray()); + var indexOffset = _indices.Count; + _indices.AddRange(TriangleUtil.FlipTriangle(Enumerable.Range(0, _vertices.Count))); + _subMeshes.Add(new SubMeshDescriptor(indexOffset, _vertices.Count)); } else { - var indices = data.GetIndices(prim.indices); - _subMeshes.Add(indices); + var indexOffset = _indices.Count; + var indices = data.GetIndices(primitive.indices); + _indices.AddRange(indices); + _subMeshes.Add(new SubMeshDescriptor(indexOffset, indices.Length)); } // material - _materialIndices.Add(prim.material); + _materialIndices.Add(primitive.material); } } @@ -490,29 +387,23 @@ namespace UniGLTF } } - // - // https://github.com/vrm-c/UniVRM/issues/610 - // - // VertexBuffer の後ろに未使用頂点がある場合に削除する - // + /// + /// https://github.com/vrm-c/UniVRM/issues/610 + /// + /// VertexBuffer の後ろに未使用頂点がある場合に削除する + /// public void DropUnusedVertices() { - var maxIndex = _subMeshes.SelectMany(x => x).Max(); - Truncate(_positions, maxIndex); - Truncate(_normals, maxIndex); - Truncate(_uv, maxIndex); - Truncate(_uv2, maxIndex); - Truncate(_colors, maxIndex); - Truncate(_boneWeights, maxIndex); -#if false - Truncate(m_tangents, maxIndex); -#endif - foreach (var blendshape in _blendShapes) + Profiler.BeginSample("MeshContext.DropUnusedVertices"); + var maxIndex = _indices.Max(); + Truncate(_vertices, maxIndex); + foreach (var blendShape in _blendShapes) { - Truncate(blendshape.Positions, maxIndex); - Truncate(blendshape.Normals, maxIndex); - Truncate(blendshape.Tangents, maxIndex); + Truncate(blendShape.Positions, maxIndex); + Truncate(blendShape.Normals, maxIndex); + Truncate(blendShape.Tangents, maxIndex); } + Profiler.EndSample(); } } } \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs index 8b9727eec..7aa83dfa5 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshImporter.cs @@ -29,8 +29,9 @@ namespace UniGLTF return sharedAttributes; } - public MeshContext ReadMesh(GltfData data, int meshIndex, IAxisInverter inverter) + internal MeshContext ReadMesh(GltfData data, int meshIndex, IAxisInverter inverter) { + Profiler.BeginSample("ReadMesh"); var gltfMesh = data.GLTF.meshes[meshIndex]; var meshContext = new MeshContext(gltfMesh.name, meshIndex); @@ -46,11 +47,12 @@ namespace UniGLTF meshContext.RenameBlendShape(gltfMesh); meshContext.DropUnusedVertices(); - + + Profiler.EndSample(); return meshContext; } - private static (Mesh, bool) _BuildMesh(MeshContext meshContext) + private static (Mesh, bool) BuildMesh(MeshContext meshContext) { meshContext.AddDefaultMaterial(); @@ -60,63 +62,15 @@ namespace UniGLTF name = meshContext.Name }; - if (meshContext.Positions.Count > ushort.MaxValue) - { - mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; - } + meshContext.UploadMeshVertices(mesh); + meshContext.UploadMeshIndices(mesh); - mesh.vertices = meshContext.Positions.ToArray(); - var recalculateNormals = false; - if (meshContext.Normals != null && meshContext.Normals.Count > 0) - { - mesh.normals = meshContext.Normals.ToArray(); - } - else - { - recalculateNormals = true; - } - - if (meshContext.UV.Count == mesh.vertexCount) - { - mesh.uv = meshContext.UV.ToArray(); - } - - if (meshContext.UV2.Count == mesh.vertexCount) - { - mesh.uv2 = meshContext.UV2.ToArray(); - } - - var recalculateTangents = true; -#if UNIGLTF_IMPORT_TANGENTS - if (meshContext.Tangents.Length > 0) - { - mesh.tangents = meshContext.Tangents.ToArray(); - recalculateTangents = false; - } -#endif - - if (meshContext.Colors.Count == mesh.vertexCount) - { - mesh.colors = meshContext.Colors.ToArray(); - } - - if (meshContext.BoneWeights.Count > 0) - { - mesh.boneWeights = meshContext.BoneWeights.ToArray(); - } - - mesh.subMeshCount = meshContext.SubMeshes.Count; - for (var i = 0; i < meshContext.SubMeshes.Count; ++i) - { - mesh.SetTriangles(meshContext.SubMeshes[i], i); - } - - if (recalculateNormals) + if (!meshContext.HasNormal) { mesh.RecalculateNormals(); } - return (mesh, recalculateTangents); + return (mesh, true); } private static async Task BuildBlendShapeAsync(IAwaitCaller awaitCaller, Mesh mesh, BlendShape blendShape, @@ -162,11 +116,13 @@ namespace UniGLTF Profiler.EndSample(); } - public static async Task BuildMeshAsync(IAwaitCaller awaitCaller, Func ctx, + internal static async Task BuildMeshAsync( + IAwaitCaller awaitCaller, + Func ctx, MeshContext meshContext) { - Profiler.BeginSample("MeshImporter._BuildMesh"); - var (mesh, recalculateTangents) = _BuildMesh(meshContext); + Profiler.BeginSample("MeshImporter.BuildMesh"); + var (mesh, recalculateTangents) = BuildMesh(meshContext); Profiler.EndSample(); if (recalculateTangents) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs new file mode 100644 index 000000000..4db319f40 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs @@ -0,0 +1,68 @@ +using System.Runtime.InteropServices; +using UnityEngine; +using UnityEngine.Rendering; + +namespace UniGLTF +{ + /// + /// インターリーブされたメッシュの頂点情報を表す構造体 + /// そのままGPUにアップロードされる + /// + [StructLayout(LayoutKind.Sequential)] + internal readonly struct MeshVertex + { + private readonly Vector3 _position; + private readonly Vector3 _normal; + private readonly Color _color; + private readonly Vector2 _texCoord0; + private readonly Vector2 _texCoord1; + private readonly float _boneWeight0; + private readonly float _boneWeight1; + private readonly float _boneWeight2; + private readonly float _boneWeight3; + private readonly ushort _boneIndex0; + private readonly ushort _boneIndex1; + private readonly ushort _boneIndex2; + private readonly ushort _boneIndex3; + + public MeshVertex( + Vector3 position, + Vector3 normal, + Vector2 texCoord0, + Vector2 texCoord1, + Color color, + ushort boneIndex0, + ushort boneIndex1, + ushort boneIndex2, + ushort boneIndex3, + float boneWeight0, + float boneWeight1, + float boneWeight2, + float boneWeight3) + { + _position = position; + _normal = normal; + _texCoord0 = texCoord0; + _texCoord1 = texCoord1; + _color = color; + _boneIndex0 = boneIndex0; + _boneIndex1 = boneIndex1; + _boneIndex2 = boneIndex2; + _boneIndex3 = boneIndex3; + _boneWeight0 = boneWeight0; + _boneWeight1 = boneWeight1; + _boneWeight2 = boneWeight2; + _boneWeight3 = boneWeight3; + } + + public static VertexAttributeDescriptor[] GetVertexAttributeDescriptor() => new[] { + new VertexAttributeDescriptor(VertexAttribute.Position), + new VertexAttributeDescriptor(VertexAttribute.Normal), + new VertexAttributeDescriptor(VertexAttribute.Color, dimension: 4), + new VertexAttributeDescriptor(VertexAttribute.TexCoord0, dimension: 2), + new VertexAttributeDescriptor(VertexAttribute.TexCoord1, dimension: 2), + new VertexAttributeDescriptor(VertexAttribute.BlendWeight, dimension: 4), + new VertexAttributeDescriptor(VertexAttribute.BlendIndices, VertexAttributeFormat.UInt16, 4), + }; + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs.meta new file mode 100644 index 000000000..8190c9154 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/MeshVertex.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0d540d8e32d54e7089a72156edb7ad80 +timeCreated: 1636526648 \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs new file mode 100644 index 000000000..7e0f9fd08 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs @@ -0,0 +1,119 @@ +using System; +using UnityEngine; + +namespace UniGLTF +{ + internal static class PrimitiveExtensions + { + public static bool HasNormal(this glTFPrimitives primitives) => primitives.attributes.NORMAL != -1; + public static bool HasTexCoord0(this glTFPrimitives primitives) => primitives.attributes.TEXCOORD_0 != -1; + public static bool HasTexCoord1(this glTFPrimitives primitives) => primitives.attributes.TEXCOORD_1 != -1; + public static bool HasSkin(this glTFPrimitives primitives) => primitives.attributes.JOINTS_0 != -1 && primitives.attributes.WEIGHTS_0 != -1; + public static bool HasColor(this glTFPrimitives primitives) => primitives.attributes.COLOR_0 != -1; + + public static Vector3[] GetPositions(this glTFPrimitives primitives, GltfData data) + { + return data.GetArrayFromAccessor(primitives.attributes.POSITION); + } + + public static Vector3[] GetNormals(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + if (!HasNormal(primitives)) return null; + var result = data.GetArrayFromAccessor(primitives.attributes.NORMAL); + if (result.Length != positionsLength) + { + throw new Exception("different length"); + } + + return result; + } + + public static Vector2[] GetTexCoords0(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + if (!HasTexCoord0(primitives)) return null; + var result = data.GetArrayFromAccessor(primitives.attributes.TEXCOORD_0); + if (result.Length != positionsLength) + { + throw new Exception("different length"); + } + + return result; + } + + public static Vector2[] GetTexCoords1(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + if (!HasTexCoord1(primitives)) return null; + var result = data.GetArrayFromAccessor(primitives.attributes.TEXCOORD_1); + if (result.Length != positionsLength) + { + throw new Exception("different length"); + } + + return result; + } + + public static Color[] GetColors(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + if (!HasColor(primitives)) return null; + + switch (data.GLTF.accessors[primitives.attributes.COLOR_0].TypeCount) + { + case 3: + { + var vec3Color = data.GetArrayFromAccessor(primitives.attributes.COLOR_0); + if (vec3Color.Length != positionsLength) + { + throw new Exception("different length"); + } + var colors = new Color[vec3Color.Length]; + + for (var index = 0; index < vec3Color.Length; index++) + { + var color = vec3Color[index]; + colors[index] = new Color(color.x, color.y, color.z); + } + + return colors; + } + case 4: + var result = data.GetArrayFromAccessor(primitives.attributes.COLOR_0); + if (result.Length != positionsLength) + { + throw new Exception("different length"); + } + + return result; + default: + throw new NotImplementedException( + $"unknown color type {data.GLTF.accessors[primitives.attributes.COLOR_0].type}"); + } + } + + public static JointsAccessor.Getter GetJoints(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + // skin + if (!HasSkin(primitives)) return null; + var (getter, length) = JointsAccessor.GetAccessor(data, primitives.attributes.JOINTS_0); + if (length != positionsLength) + { + throw new Exception("different length"); + } + + return getter; + + } + + public static WeightsAccessor.Getter GetWeights(this glTFPrimitives primitives, GltfData data, int positionsLength) + { + // skin + if (!HasSkin(primitives)) return null; + var (getter, length) = WeightsAccessor.GetAccessor(data, primitives.attributes.WEIGHTS_0); + if (length != positionsLength) + { + throw new Exception("different length"); + } + + return getter; + } + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs.meta b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs.meta new file mode 100644 index 000000000..bb9ad2215 --- /dev/null +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/MeshIO/PrimitiveExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 867e7d22991044cd921d5479269142f2 +timeCreated: 1636536120 \ No newline at end of file