Esempio n. 1
0
        private static byte[][] GetGltfModelBuffers(Gltf gltf, string filePath)
        {
            byte[][] buffers = new byte[gltf.Buffers.Length][];

            for (int i = 0; i < gltf.Buffers.Length; i++)
            {
                buffers[i] = gltf.LoadBinaryBuffer(i, Path.Combine(Path.GetDirectoryName(filePath), gltf.Buffers[i].Uri ?? Path.GetFileName(filePath)));
            }

            return(buffers);
        }
Esempio n. 2
0
        private void FetchBuffers(Gltf gltfFile, string gltfPath, IEnumerable <int> bufferIndices)
        {
            foreach (var bufferIndex in bufferIndices)
            {
                var buffer = gltfFile.Buffers[bufferIndex];

                if (_bufferFileData.ContainsKey(buffer))
                {
                    continue;
                }

                var bufferName = string.IsNullOrEmpty(buffer.Uri)
                    ? $"buffer#{bufferIndex}"
                    : buffer.Uri.Substring(0, Math.Min(100, buffer.Uri.Length));

                Log.WriteLine($"Fetching buffer {bufferName}...");

                var data = gltfFile.LoadBinaryBuffer(bufferIndex, gltfPath);
                _bufferFileData.Add(buffer, data);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Opens a stream to the image referenced by a specific <code>Schema.Image</code>
        /// </summary>
        /// <param name="model">The <code>Schema.Gltf</code> model containing the <code>Schema.Image</code></param>
        /// <param name="imageIndex">The index of the image</param>
        /// <param name="externalReferenceSolver">An user provided lambda function to resolve external assets</param>
        /// <returns>An open stream to the image</returns>
        /// <remarks>
        /// Images can be stored in three different ways:
        /// - As stand alone files.
        /// - As a part of binary buffer accessed via bufferView.
        /// - Encoded to Base64 within the JSON.
        ///
        /// The external reference solver funcion is called when the image is stored in an external file,
        /// or when the image is in the glb binary chunk, in which case, the Argument of the function will be Null.
        ///
        /// The Lambda function must return the byte array of the requested file or buffer.
        /// </remarks>
        public static Stream OpenImageFile(this Gltf model, int imageIndex, Func <string, Byte[]> externalReferenceSolver)
        {
            var image = model.Images[imageIndex];

            if (image.BufferView.HasValue)
            {
                var bufferView = model.BufferViews[image.BufferView.Value];

                var bufferBytes = model.LoadBinaryBuffer(bufferView.Buffer, externalReferenceSolver, bufferView.ByteOffset);

                return(new MemoryStream(bufferBytes, bufferView.ByteOffset, bufferView.ByteLength));
            }

            if (image.Uri.StartsWith("data:image/"))
            {
                return(OpenEmbeddedImage(image));
            }

            var imageData = externalReferenceSolver(image.Uri);

            return(new MemoryStream(imageData));
        }
Esempio n. 4
0
        private void EnsureBufferIsLoaded(int index)
        {
            if (loadedBuffers[index] == null)
            {
                //load full buffer
                string uri = gltf.Buffers[index].Uri;
                if (string.IsNullOrEmpty(uri))//glb
                {
                    loadedBuffers[index] = gltf.LoadBinaryBuffer(index, _path);
                }
                else if (uri.StartsWith("data", StringComparison.Ordinal))
                {
                    loadedBuffers[index] = LoadDataUri(gltf.Buffers[index]); //TODO: check this func=>System.Buffers.Text.Base64.EncodeToUtf8InPlace
                }
                else
                {
                    loadedBuffers[index] = File.ReadAllBytes(Path.Combine(baseDirectory, gltf.Buffers[index].Uri));
                }

                bufferHandles[index] = GCHandle.Alloc(loadedBuffers[index], GCHandleType.Pinned);
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Writes a <code>Schema.Gltf</code> model to a writable binary writer and pack all data into the model
        /// </summary>
        /// <param name="model"><code>Schema.Gltf</code> model</param>
        /// <param name="binaryWriter">Binary Writer</param>
        /// <param name="gltfFilePath">Source file path used to load the model</param>
        /// <param name="glbBinChunck">optional GLB-stored Buffer (BIN data file). If null, then the first buffer Uri must point to a BIN file.</param>
        public static void SaveBinaryModelPacked(this Gltf model, BinaryWriter binaryWriter, string gltfFilePath, byte[] glbBinChunck = null)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            byte[] binBufferData = null;

            using (var memoryStream = new MemoryStream())
            {
                var bufferViews = new List <BufferView>();
                var bufferData  = new Dictionary <int, byte[]>();

                if (model.BufferViews != null)
                {
                    foreach (var bufferView in model.BufferViews)
                    {
                        memoryStream.Align(4);

                        var byteOffset = memoryStream.Position;

                        byte[] data;
                        if (!bufferData.TryGetValue(bufferView.Buffer, out data))
                        {
                            // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#glb-stored-buffer
                            /// "glTF Buffer referring to GLB-stored BIN chunk, must have buffer.uri
                            /// property undefined, and it must be the first element of buffers array"
                            data = bufferView.Buffer == 0 && glbBinChunck != null
                                        ? glbBinChunck
                                        : model.LoadBinaryBuffer(bufferView.Buffer, gltfFilePath, bufferView.ByteOffset);

                            bufferData.Add(bufferView.Buffer, data);
                        }

                        memoryStream.Write(data, bufferView.ByteOffset, bufferView.ByteLength);

                        bufferView.Buffer     = 0;
                        bufferView.ByteOffset = (int)byteOffset;
                        bufferViews.Add(bufferView);
                    }
                }

                if (model.Images != null)
                {
                    for (var index = 0; index < model.Images.Length; index++)
                    {
                        var byteOffset = memoryStream.Position;

                        var data = model.OpenImageFile(index, gltfFilePath);
                        data.CopyTo(memoryStream);

                        var image = model.Images[index];
                        image.BufferView = bufferViews.Count;
                        image.MimeType   = GetMimeType(image.Uri);
                        image.Uri        = null;

                        bufferViews.Add(new BufferView
                        {
                            Buffer     = 0,
                            ByteOffset = (int)byteOffset,
                            ByteLength = (int)data.Length,
                        });
                    }
                }

                if (bufferViews.Any())
                {
                    model.BufferViews = bufferViews.ToArray();

                    model.Buffers = new[]
                    {
                        new glTFLoader.Schema.Buffer
                        {
                            ByteLength = (int)memoryStream.Length
                        }
                    };

                    binBufferData = memoryStream.ToArray();
                }
            }

            Interface.SaveBinaryModel(model, binBufferData, binaryWriter);
        }
Esempio n. 6
0
        public Core.Entities.Mesh LoadFromFile(string path)
        {
            if (!path.EndsWith("gltf") && !path.EndsWith("glb"))
            {
                return(null);
            }

            Gltf deserializedFile = Interface.LoadModel(path);

            //Only one mesh currently supported.
            Mesh[] meshes = deserializedFile.Meshes;

            Core.Entities.Mesh loadedModel = new Core.Entities.Mesh(_recalculateNormals);

            // read all buffers
            for (int i = 0; i < deserializedFile.Buffers?.Length; i++)
            {
                byte[] bufferBytes           = deserializedFile.LoadBinaryBuffer(i, path);
                int    indecesAttributevalue = meshes[0].Primitives[0].Indices ?? 0;
                int    indecesBufferView     = deserializedFile.Accessors[indecesAttributevalue].BufferView ?? 0;
                int[]  indeces =
                    bufferBytes.ParseBufferViews(deserializedFile.Accessors[indecesAttributevalue],
                                                 deserializedFile.BufferViews[indecesBufferView]);
                foreach (KeyValuePair <string, int> attribute in deserializedFile.Meshes[0].Primitives[0].Attributes)
                {
                    Console.WriteLine(attribute.Key);
                }

                AttributeParser posParser     = new AttributeParser(0, 0, deserializedFile, bufferBytes, "POSITION");
                AttributeParser normParser    = new AttributeParser(0, 0, deserializedFile, bufferBytes, "NORMAL");
                AttributeParser uv0Parser     = new AttributeParser(0, 0, deserializedFile, bufferBytes, "TEXCOORD_0");
                AttributeParser uv1Parser     = new AttributeParser(0, 0, deserializedFile, bufferBytes, "TEXCOORD_1");
                AttributeParser tangentParser = new AttributeParser(0, 0, deserializedFile, bufferBytes, "TANGENT");

                //Animations
                AttributeParser jointsParser  = new AttributeParser(0, 0, deserializedFile, bufferBytes, "JOINTS_0");
                AttributeParser weightsParser = new AttributeParser(0, 0, deserializedFile, bufferBytes, "WEIGHTS_0");

                List <Vector3> vertexCoords  = posParser.Parse() ? posParser.ParsedAttribute : null;
                List <Vector3> normalCoords  = normParser.Parse() ? normParser.ParsedAttribute : null;
                List <Vector2> uv0Coords     = uv0Parser.Parse() ? uv0Parser.ParsedAttribute : null;
                List <Vector2> uv1Coords     = uv1Parser.Parse() ? uv1Parser.ParsedAttribute : null;
                List <Vector4> tangentCoords = tangentParser.Parse() ? tangentParser.ParsedAttribute : null;

                //Animations
                List <Vector4> jointsValues  = jointsParser.Parse() ? jointsParser.ParsedAttribute : null;
                List <Vector4> weightsValues = weightsParser.Parse() ? weightsParser.ParsedAttribute : null;

                List <Vector3> decodedVertices = new List <Vector3>();
                List <Vector3> decodedNormals  = new List <Vector3>();
                List <Vector2> decodedUvCoords = new List <Vector2>();


                for (int j = 0; j < indeces.Length; j++)
                {
                    decodedVertices.Add(vertexCoords == null || vertexCoords.Count() == 0 ? Vector3.Zero : vertexCoords[indeces[j]]);
                    decodedNormals.Add(normalCoords == null || normalCoords.Count() == 0 ? Vector3.Zero : normalCoords[indeces[j]]);
                    decodedUvCoords.Add(uv0Coords == null || uv0Coords.Count() == 0 ? Vector2.Zero : uv0Coords[indeces[j]]);
                }

                loadedModel.Vertices = decodedVertices.ToArray();
                loadedModel.Normals  = decodedNormals.ToArray();
                loadedModel.UvCoords = decodedUvCoords.ToArray();
                loadedModel.Indeces  = indeces;
            }
            return(loadedModel);
        }