Example #1
0
        void CreateGameObjects(Transform parent, byte[] bytes)
        {
            var primitives         = new List <Primitive>(gltf.meshes.Length);
            var meshPrimitiveIndex = new int[gltf.meshes.Length + 1];

            Texture2D[] images = null;

            resources = new List <UnityEngine.Object>();

            if (gltf.images != null)
            {
                images = new Texture2D[gltf.images.Length];
                for (int i = 0; i < images.Length; i++)
                {
                    var img = gltf.images[i];
                    if (img.mimeType == "image/jpeg" || img.mimeType == "image/png")
                    {
                        if (img.bufferView >= 0)
                        {
                            var bufferView = gltf.bufferViews[img.bufferView];
                            var chunk      = binChunks[bufferView.buffer];
                            var imgBytes   = Extractor.CreateBufferViewCopy(bufferView, chunk, bytes);
                            var txt        = new UnityEngine.Texture2D(4, 4);
                            txt.name = string.IsNullOrEmpty(img.name) ? string.Format("glb embed texture {0}", i) : img.name;
                            txt.LoadImage(imgBytes);
                            images[i] = txt;
                            resources.Add(txt);
                        }
                        else
                        if (!string.IsNullOrEmpty(img.uri))
                        {
                            Debug.LogError("Loading from URI not supported");
                        }
                    }
                    else
                    {
                        Debug.LogErrorFormat("Unknown image mime type {0}", img.mimeType);
                    }
                }
            }

            if (gltf.materials != null)
            {
                materials = new UnityEngine.Material[gltf.materials.Length];
                for (int i = 0; i < materials.Length; i++)
                {
                    materials[i] = materialGenerator.GenerateMaterial(gltf.materials[i], gltf.textures, images, resources);
                }
            }

            //foreach( var mesh in gltf.meshes ) {
            for (int meshIndex = 0; meshIndex < gltf.meshes.Length; meshIndex++)
            {
                var mesh = gltf.meshes[meshIndex];
                meshPrimitiveIndex[meshIndex] = primitives.Count;

                foreach (var primitive in mesh.primitives)
                {
                    // index
                    var accessor   = gltf.accessors[primitive.indices];
                    var bufferView = gltf.bufferViews[accessor.bufferView];
                    var buffer     = bufferView.buffer;

                    GlbBinChunk chunk = binChunks[buffer];
                    Assert.AreEqual(accessor.typeEnum, GLTFAccessorAttributeType.SCALAR);
                    //Assert.AreEqual(accessor.count * GetLength(accessor.typeEnum) * 4 , (int) chunk.length);
                    int[] indices = null;
                    switch (accessor.componentType)
                    {
                    case GLTFComponentType.UnsignedByte:
                        indices = Extractor.GetIndicesUInt8(bytes, accessor.byteOffset + bufferView.byteOffset + chunk.start, accessor.count);
                        break;

                    case GLTFComponentType.UnsignedShort:
                        indices = Extractor.GetIndicesUInt16(bytes, accessor.byteOffset + bufferView.byteOffset + chunk.start, accessor.count);
                        break;

                    case GLTFComponentType.UnsignedInt:
                        indices = Extractor.GetIndicesUInt32(bytes, accessor.byteOffset + bufferView.byteOffset + chunk.start, accessor.count);
                        break;

                    default:
                        Debug.LogErrorFormat("Invalid index format {0}", accessor.componentType);
                        break;
                    }

                    // position
                    int pos = primitive.attributes.POSITION;
                    Assert.IsTrue(pos >= 0);
                    #if DEBUG
                    Assert.AreEqual(GetAccessorTye(gltf.accessors[pos].typeEnum), typeof(Vector3));
#endif
                    var positions = gltf.IsAccessorInterleaved(pos)
                                ? GetAccessorDataInterleaved <Vector3>(pos, ref bytes, Extractor.GetVector3sInterleaved)
                                : GetAccessorData <Vector3>(pos, ref bytes, Extractor.GetVector3s);

                    Vector3[] normals = null;
                    if (primitive.attributes.NORMAL >= 0)
                    {
                        #if DEBUG
                        Assert.AreEqual(GetAccessorTye(gltf.accessors[primitive.attributes.NORMAL].typeEnum), typeof(Vector3));
                        #endif
                        normals = gltf.IsAccessorInterleaved(pos)
                                                    ? GetAccessorDataInterleaved <Vector3>(primitive.attributes.NORMAL, ref bytes, Extractor.GetVector3sInterleaved)
                                                    : GetAccessorData <Vector3>(primitive.attributes.NORMAL, ref bytes, Extractor.GetVector3s);
                    }

                    Vector2[] uvs0 = GetUvs(primitive.attributes.TEXCOORD_0, ref bytes);
                    Vector2[] uvs1 = GetUvs(primitive.attributes.TEXCOORD_1, ref bytes);

                    Vector4[] tangents = null;
                    if (primitive.attributes.TANGENT >= 0)
                    {
                        #if DEBUG
                        Assert.AreEqual(GetAccessorTye(gltf.accessors[primitive.attributes.TANGENT].typeEnum), typeof(Vector4));
                        #endif
                        tangents = gltf.IsAccessorInterleaved(pos)
                                            ? GetAccessorDataInterleaved <Vector4>(primitive.attributes.TANGENT, ref bytes, Extractor.GetVector4sInterleaved)
                                                : GetAccessorData <Vector4>(primitive.attributes.TANGENT, ref bytes, Extractor.GetVector4s);
                    }

                    Color32[] colors32;
                    Color[]   colors;
                    GetColors(primitive.attributes.COLOR_0, ref bytes, out colors32, out colors);

                    var msh = new UnityEngine.Mesh();
                    msh.name     = mesh.name;
                    msh.vertices = positions;
                    msh.SetIndices(indices, MeshTopology.Triangles, 0);
                    if (uvs0 != null)
                    {
                        msh.uv = uvs0;
                    }
                    if (uvs1 != null)
                    {
                        msh.uv2 = uvs1;
                    }
                    if (normals != null)
                    {
                        msh.normals = normals;
                    }
                    else
                    {
                        msh.RecalculateNormals();
                    }
                    if (colors != null)
                    {
                        msh.colors = colors;
                    }
                    else if (colors32 != null)
                    {
                        msh.colors32 = colors32;
                    }
                    if (tangents != null)
                    {
                        msh.tangents = tangents;
                    }
                    else
                    {
                        msh.RecalculateTangents();
                    }
                    primitives.Add(new Primitive(msh, primitive.material));
                    resources.Add(msh);
                }
            }

            meshPrimitiveIndex[gltf.meshes.Length] = primitives.Count;

            var nodes     = new Transform[gltf.nodes.Length];
            var relations = new Dictionary <uint, uint>();

            for (uint nodeIndex = 0; nodeIndex < gltf.nodes.Length; nodeIndex++)
            {
                var node = gltf.nodes[nodeIndex];

                if (node.children == null && node.mesh < 0)
                {
                    continue;
                }

                var go = new GameObject(node.name ?? "Node");
                nodes[nodeIndex] = go.transform;

                if (node.children != null)
                {
                    foreach (var child in node.children)
                    {
                        relations[child] = nodeIndex;
                    }
                }

                if (node.matrix != null)
                {
                    Matrix4x4 m = new Matrix4x4();
                    m.m00 = node.matrix[0];
                    m.m10 = node.matrix[1];
                    m.m20 = node.matrix[2];
                    m.m30 = node.matrix[3];
                    m.m01 = node.matrix[4];
                    m.m11 = node.matrix[5];
                    m.m21 = node.matrix[6];
                    m.m31 = node.matrix[7];
                    m.m02 = node.matrix[8];
                    m.m12 = node.matrix[9];
                    m.m22 = node.matrix[10];
                    m.m32 = node.matrix[11];
                    m.m03 = node.matrix[12];
                    m.m13 = node.matrix[13];
                    m.m23 = node.matrix[14];
                    m.m33 = node.matrix[15];

                    if (m.ValidTRS())
                    {
                        go.transform.localPosition = new Vector3(m.m03, m.m13, m.m23);
                        go.transform.localRotation = m.rotation;
                        go.transform.localScale    = m.lossyScale;
                    }
                    else
                    {
                        Debug.LogErrorFormat("Invalid matrix on node {0}", nodeIndex);
                    }
                }
                else
                {
                    if (node.translation != null)
                    {
                        Assert.AreEqual(node.translation.Length, 3);
                        go.transform.localPosition = new Vector3(
                            node.translation[0],
                            node.translation[1],
                            node.translation[2]
                            );
                    }
                    if (node.rotation != null)
                    {
                        Assert.AreEqual(node.rotation.Length, 4);
                        go.transform.localRotation = new Quaternion(
                            node.rotation[0],
                            node.rotation[1],
                            node.rotation[2],
                            node.rotation[3]
                            );
                    }
                    if (node.scale != null)
                    {
                        Assert.AreEqual(node.scale.Length, 3);
                        go.transform.localScale = new Vector3(
                            node.scale[0],
                            node.scale[1],
                            node.scale[2]
                            );
                    }
                }

                if (node.mesh >= 0)
                {
                    int        end    = meshPrimitiveIndex[node.mesh + 1];
                    GameObject meshGo = null;
                    for (int i = meshPrimitiveIndex[node.mesh]; i < end; i++)
                    {
                        if (meshGo == null)
                        {
                            meshGo = go;
                        }
                        else
                        {
                            meshGo = new GameObject("Primitive");
                            meshGo.transform.SetParent(go.transform, false);
                        }
                        var mf = meshGo.AddComponent <MeshFilter>();
                        mf.mesh = primitives[i].mesh;
                        var mr = meshGo.AddComponent <MeshRenderer>();

                        int materialIndex = primitives[i].materialIndex;
                        if (materials != null && materialIndex >= 0 && materialIndex < materials.Length)
                        {
                            mr.material = materials[primitives[i].materialIndex];
                        }
                        else
                        {
                            mr.material = materialGenerator.GetDefaultMaterial();
                        }
                    }
                }
            }

            foreach (var rel in relations)
            {
                nodes[rel.Key]?.SetParent(nodes[rel.Value], false);
            }

            foreach (var scene in gltf.scenes)
            {
                var go = new GameObject(scene.name ?? "Scene");
                go.transform.SetParent(parent, false);

                // glTF to unity space ( -z forward to z forward )
                go.transform.localScale = new Vector3(1, 1, -1);

                foreach (var nodeIndex in scene.nodes)
                {
                    nodes[nodeIndex]?.SetParent(go.transform, false);
                }
            }

            foreach (var bv in gltf.bufferViews)
            {
                if (gltf.buffers[bv.buffer].uri == null)
                {
                }
            }
        }
Example #2
0
        bool CreateGameObjects(Root gltf, Transform parent)
        {
            var primitives         = new List <Primitive>(gltf.meshes.Length);
            var meshPrimitiveIndex = new int[gltf.meshes.Length + 1];

            resources = new List <UnityEngine.Object>();

            if (gltf.images != null)
            {
                if (images == null)
                {
                    images = new Texture2D[gltf.images.Length];
                }
                else
                {
                    Assert.AreEqual(images.Length, gltf.images.Length);
                }
                for (int i = 0; i < images.Length; i++)
                {
                    if (images[i] != null)
                    {
                        resources.Add(images[i]);
                    }
                    var  img            = gltf.images[i];
                    bool knownImageType = false;
                    if (string.IsNullOrEmpty(img.mimeType))
                    {
                        Debug.LogWarning("Image is missing mime type");
                        knownImageType = img.uri.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
                                         img.uri.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
                                         img.uri.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase);
                    }
                    else
                    {
                        knownImageType = img.mimeType == "image/jpeg" || img.mimeType == "image/png";
                    }

                    if (knownImageType)
                    {
                        if (img.bufferView >= 0)
                        {
                            var bufferView = gltf.bufferViews[img.bufferView];
                            var buffer     = GetBuffer(bufferView.buffer);
                            var chunk      = binChunks[bufferView.buffer];
                            var imgBytes   = Extractor.CreateBufferViewCopy(bufferView, chunk, buffer);
                            var txt        = new UnityEngine.Texture2D(4, 4);
                            txt.name = string.IsNullOrEmpty(img.name) ? string.Format("glb embed texture {0}", i) : img.name;
                            txt.LoadImage(imgBytes);
                            images[i] = txt;
                            resources.Add(txt);
                        }
                    }
                }
            }

            if (gltf.materials != null)
            {
                materials = new UnityEngine.Material[gltf.materials.Length];
                for (int i = 0; i < materials.Length; i++)
                {
                    materials[i] = materialGenerator.GenerateMaterial(gltf.materials[i], gltf.textures, images, resources);
                }
            }

            //foreach( var mesh in gltf.meshes ) {
            for (int meshIndex = 0; meshIndex < gltf.meshes.Length; meshIndex++)
            {
                var mesh = gltf.meshes[meshIndex];
                meshPrimitiveIndex[meshIndex] = primitives.Count;

                foreach (var primitive in mesh.primitives)
                {
                    // index
                    var accessor    = gltf.accessors[primitive.indices];
                    var bufferView  = gltf.bufferViews[accessor.bufferView];
                    var bufferIndex = bufferView.buffer;
                    var buffer      = GetBuffer(bufferIndex);

                    GlbBinChunk chunk = binChunks[bufferIndex];
                    Assert.AreEqual(accessor.typeEnum, GLTFAccessorAttributeType.SCALAR);
                    //Assert.AreEqual(accessor.count * GetLength(accessor.typeEnum) * 4 , (int) chunk.length);
                    int[] indices = null;
                    switch (accessor.componentType)
                    {
                    case GLTFComponentType.UnsignedByte:
                        indices = Extractor.GetIndicesUInt8(buffer, accessor.byteOffset + bufferView.byteOffset + chunk.start, accessor.count);
                        break;

                    case GLTFComponentType.UnsignedShort:
                        indices = Extractor.GetIndicesUInt16(buffer, accessor.byteOffset + bufferView.byteOffset + chunk.start, accessor.count);
                        break;

                    case GLTFComponentType.UnsignedInt:
                        indices = Extractor.GetIndicesUInt32(buffer, accessor.byteOffset + bufferView.byteOffset + chunk.start, accessor.count);
                        break;

                    default:
                        Debug.LogErrorFormat("Invalid index format {0}", accessor.componentType);
                        return(false);
                    }

                    #if DEBUG
                    if (accessor.min != null && accessor.min.Length > 0 && accessor.max != null && accessor.max.Length > 0)
                    {
                        int minInt   = (int)accessor.min[0];
                        int maxInt   = (int)accessor.max[0];
                        int minIndex = int.MaxValue;
                        int maxIndex = int.MinValue;
                        foreach (var index in indices)
                        {
                            Assert.IsTrue(index >= minInt);
                            Assert.IsTrue(index <= maxInt);
                            minIndex = Math.Min(minIndex, index);
                            maxIndex = Math.Max(maxIndex, index);
                        }
                        if (minIndex != minInt ||
                            maxIndex != maxInt
                            )
                        {
                            Debug.LogErrorFormat("Faulty index bounds: is {0}:{1} expected:{2}:{3}", minIndex, maxIndex, minInt, maxInt);
                        }
                    }
                    #endif

                    // position
                    int pos = primitive.attributes.POSITION;
                    Assert.IsTrue(pos >= 0);
                    #if DEBUG
                    Assert.AreEqual(GetAccessorTye(gltf.accessors[pos].typeEnum), typeof(Vector3));
                    #endif
                    var positions = gltf.IsAccessorInterleaved(pos)
                                ? GetAccessorDataInterleaved <Vector3>(gltf, pos, ref buffer, Extractor.GetVector3sInterleaved)
                                : GetAccessorData <Vector3>(gltf, pos, ref buffer, Extractor.GetVector3s);

                    #if DEBUG
                    var     posAcc = gltf.accessors[pos];
                    Vector3 minPos = new Vector3((float)posAcc.min[0], (float)posAcc.min[1], (float)posAcc.min[2]);
                    Vector3 maxPos = new Vector3((float)posAcc.max[0], (float)posAcc.max[1], (float)posAcc.max[2]);
                    foreach (var p in positions)
                    {
                        if (!(p.x >= minPos.x &&
                              p.y >= minPos.y &&
                              p.z >= minPos.z &&
                              p.x <= maxPos.x &&
                              p.y <= maxPos.y &&
                              p.z <= maxPos.z
                              ))
                        {
                            Debug.LogError("Vertex outside of limits");
                            break;
                        }
                    }

                    var pUsage = new int[positions.Length];
                    foreach (var index in indices)
                    {
                        pUsage[index] += 1;
                    }
                    int pMin = int.MaxValue;
                    foreach (var u in pUsage)
                    {
                        pMin = Math.Min(pMin, u);
                    }
                    if (pMin < 1)
                    {
                        Debug.LogError("Unused vertices");
                    }
                    #endif


                    Vector3[] normals = null;
                    if (primitive.attributes.NORMAL >= 0)
                    {
                        #if DEBUG
                        Assert.AreEqual(GetAccessorTye(gltf.accessors[primitive.attributes.NORMAL].typeEnum), typeof(Vector3));
                        #endif
                        normals = gltf.IsAccessorInterleaved(pos)
                                                    ? GetAccessorDataInterleaved <Vector3>(gltf, primitive.attributes.NORMAL, ref buffer, Extractor.GetVector3sInterleaved)
                                                    : GetAccessorData <Vector3>(gltf, primitive.attributes.NORMAL, ref buffer, Extractor.GetVector3s);
                    }

                    Vector2[] uvs0 = GetUvs(gltf, primitive.attributes.TEXCOORD_0, ref buffer);
                    Vector2[] uvs1 = GetUvs(gltf, primitive.attributes.TEXCOORD_1, ref buffer);

                    Vector4[] tangents = null;
                    if (primitive.attributes.TANGENT >= 0)
                    {
                        #if DEBUG
                        Assert.AreEqual(GetAccessorTye(gltf.accessors[primitive.attributes.TANGENT].typeEnum), typeof(Vector4));
                        #endif
                        tangents = gltf.IsAccessorInterleaved(pos)
                                            ? GetAccessorDataInterleaved <Vector4>(gltf, primitive.attributes.TANGENT, ref buffer, Extractor.GetVector4sInterleaved)
                                                : GetAccessorData <Vector4>(gltf, primitive.attributes.TANGENT, ref buffer, Extractor.GetVector4s);
                    }

                    Color32[] colors32;
                    Color[]   colors;
                    GetColors(gltf, primitive.attributes.COLOR_0, ref buffer, out colors32, out colors);

                    var msh = new UnityEngine.Mesh();
                    if (positions.Length > 65536)
                    {
#if UNITY_2017_3_OR_NEWER
                        msh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
#else
                        throw new System.Exception("Meshes with more than 65536 vertices are only supported from Unity 2017.3 onwards.");
#endif
                    }
                    msh.name     = mesh.name;
                    msh.vertices = positions;
                    msh.SetIndices(indices, MeshTopology.Triangles, 0);
                    if (uvs0 != null)
                    {
                        msh.uv = uvs0;
                    }
                    if (uvs1 != null)
                    {
                        msh.uv2 = uvs1;
                    }
                    if (normals != null)
                    {
                        msh.normals = normals;
                    }
                    else
                    {
                        msh.RecalculateNormals();
                    }
                    if (colors != null)
                    {
                        msh.colors = colors;
                    }
                    else if (colors32 != null)
                    {
                        msh.colors32 = colors32;
                    }
                    if (tangents != null)
                    {
                        msh.tangents = tangents;
                    }
                    else
                    {
                        msh.RecalculateTangents();
                    }
                    primitives.Add(new Primitive(msh, primitive.material));
                    resources.Add(msh);
                }
            }

            meshPrimitiveIndex[gltf.meshes.Length] = primitives.Count;

            var nodes     = new Transform[gltf.nodes.Length];
            var relations = new Dictionary <uint, uint>();

            for (uint nodeIndex = 0; nodeIndex < gltf.nodes.Length; nodeIndex++)
            {
                var node = gltf.nodes[nodeIndex];

                if (node.children == null && node.mesh < 0)
                {
                    continue;
                }

                var go = new GameObject(node.name ?? "Node");
                nodes[nodeIndex] = go.transform;

                if (node.children != null)
                {
                    foreach (var child in node.children)
                    {
                        relations[child] = nodeIndex;
                    }
                }

                if (node.matrix != null)
                {
                    Matrix4x4 m = new Matrix4x4();
                    m.m00 = node.matrix[0];
                    m.m10 = node.matrix[1];
                    m.m20 = node.matrix[2];
                    m.m30 = node.matrix[3];
                    m.m01 = node.matrix[4];
                    m.m11 = node.matrix[5];
                    m.m21 = node.matrix[6];
                    m.m31 = node.matrix[7];
                    m.m02 = node.matrix[8];
                    m.m12 = node.matrix[9];
                    m.m22 = node.matrix[10];
                    m.m32 = node.matrix[11];
                    m.m03 = node.matrix[12];
                    m.m13 = node.matrix[13];
                    m.m23 = node.matrix[14];
                    m.m33 = node.matrix[15];

                    if (m.ValidTRS())
                    {
                        go.transform.localPosition = new Vector3(m.m03, m.m13, m.m23);
                        go.transform.localRotation = m.rotation;
                        go.transform.localScale    = m.lossyScale;
                    }
                    else
                    {
                        Debug.LogErrorFormat("Invalid matrix on node {0}", nodeIndex);
                        return(false);
                    }
                }
                else
                {
                    if (node.translation != null)
                    {
                        Assert.AreEqual(node.translation.Length, 3);
                        go.transform.localPosition = new Vector3(
                            node.translation[0],
                            node.translation[1],
                            node.translation[2]
                            );
                    }
                    if (node.rotation != null)
                    {
                        Assert.AreEqual(node.rotation.Length, 4);
                        go.transform.localRotation = new Quaternion(
                            node.rotation[0],
                            node.rotation[1],
                            node.rotation[2],
                            node.rotation[3]
                            );
                    }
                    if (node.scale != null)
                    {
                        Assert.AreEqual(node.scale.Length, 3);
                        go.transform.localScale = new Vector3(
                            node.scale[0],
                            node.scale[1],
                            node.scale[2]
                            );
                    }
                }

                if (node.mesh >= 0)
                {
                    int        end    = meshPrimitiveIndex[node.mesh + 1];
                    GameObject meshGo = null;
                    for (int i = meshPrimitiveIndex[node.mesh]; i < end; i++)
                    {
                        if (meshGo == null)
                        {
                            meshGo = go;
                        }
                        else
                        {
                            meshGo = new GameObject("Primitive");
                            meshGo.transform.SetParent(go.transform, false);
                        }
                        var mf = meshGo.AddComponent <MeshFilter>();
                        mf.mesh = primitives[i].mesh;
                        var mr = meshGo.AddComponent <MeshRenderer>();

                        int materialIndex = primitives[i].materialIndex;
                        if (materials != null && materialIndex >= 0 && materialIndex < materials.Length)
                        {
                            mr.material = materials[primitives[i].materialIndex];
                        }
                        else
                        {
                            mr.material = materialGenerator.GetDefaultMaterial();
                        }
                    }
                }
            }

            foreach (var rel in relations)
            {
                nodes[rel.Key]?.SetParent(nodes[rel.Value], false);
            }

            foreach (var scene in gltf.scenes)
            {
                var go = new GameObject(scene.name ?? "Scene");
                go.transform.SetParent(parent, false);

                // glTF to unity space ( -z forward to z forward )
                go.transform.localScale = new Vector3(1, 1, -1);

                foreach (var nodeIndex in scene.nodes)
                {
                    nodes[nodeIndex]?.SetParent(go.transform, false);
                }
            }

            foreach (var bv in gltf.bufferViews)
            {
                if (gltf.buffers[bv.buffer].uri == null)
                {
                }
            }
            return(true);
        }