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); }
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); } }
/// <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)); }
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); } }
/// <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); }
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); }