From 46a766ac38581250b8948719ad89464562fd15a6 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Tue, 23 Jun 2026 06:14:40 -0700 Subject: [PATCH 1/5] Fix a lot of typos --- Editor/Scripts/GLTFImporter.cs | 4 +- .../Plugins/GLTFSerialization/GLBBuilder.cs | 10 ++-- .../Plugins/GLTFSerialization/GLTFHelpers.cs | 4 +- .../Plugins/GLTFSerialization/GLTFParser.cs | 2 +- .../Utilities/StreamExtensions.cs | 2 +- Runtime/Scripts/GLTFSceneExporter.cs | 36 ++++++------ Runtime/Scripts/GLTFSceneImporter.cs | 58 +++++++++---------- Runtime/Scripts/GLTFSettings.cs | 4 +- .../SceneExporter/ExporterAccessors.cs | 12 ++-- .../SceneImporter/ImporterAnimation.cs | 2 +- .../Scripts/SceneImporter/ImporterMeshes.cs | 10 ++-- .../Scripts/SceneImporter/ImporterSkinning.cs | 2 +- 12 files changed, 73 insertions(+), 73 deletions(-) diff --git a/Editor/Scripts/GLTFImporter.cs b/Editor/Scripts/GLTFImporter.cs index e21ffbf67..482c8b637 100644 --- a/Editor/Scripts/GLTFImporter.cs +++ b/Editor/Scripts/GLTFImporter.cs @@ -195,7 +195,7 @@ public class AnimationClipImportInfo // public float endTime; } -#if !UNIYT_2020_2_OR_NEWER +#if !UNITY_2020_2_OR_NEWER private class NonReorderableAttribute : Attribute {} #endif @@ -761,7 +761,7 @@ string GetUniqueName(string desiredName) foreach (var mat in materials) { if (!mat) continue; - // ensure materials that are overriden aren't shown in the hierarchy. + // ensure materials that are overridden aren't shown in the hierarchy. var si = new SourceAssetIdentifier(mat); if (map.TryGetValue(si, out var remappedMaterial) && remappedMaterial) mat.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; diff --git a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs index bccb64658..4ff227df1 100644 --- a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs +++ b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs @@ -30,7 +30,7 @@ private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, F long proposedLength = gltfJsonStream.Length + GLTFParser.HEADER_SIZE + GLTFParser.CHUNK_HEADER_SIZE; if (gltfJsonStream.Length > uint.MaxValue) { - throw new ArgumentException("Serialized root cannot exceed uint.maxvalue", nameof(root)); + throw new ArgumentException("Serialized root cannot exceed uint.MaxValue", nameof(root)); } uint proposedLengthAsUint = (uint)proposedLength; glbOutStream.SetLength(proposedLengthAsUint); @@ -195,7 +195,7 @@ private static GLBObject _ConstructFromEmptyStream(Stream inStream, long streamS /// /// Saves out the GLBObject to its own stream - /// The GLBObject stream will be updated to be the output stream. Callers are reponsible for handling Stream lifetime + /// The GLBObject stream will be updated to be the output stream. Callers are responsible for handling Stream lifetime /// /// The GLB to flush to the output stream and update /// Optional root to replace the one in the glb @@ -233,7 +233,7 @@ public static void UpdateStream(GLBObject glb) glb.SetJsonChunkStartPosition(GLTFParser.HEADER_SIZE); } - // new proposed length = propsoedJsonBufferSize - currentJsonBufferSize + totalFileLength + // new proposed length = proposedJsonBufferSize - currentJsonBufferSize + totalFileLength long proposedLength = amountToAddToFile + glb.Header.FileLength; if (proposedLength > uint.MaxValue) { @@ -392,8 +392,8 @@ public static void MergeGLBs(GLBObject mergeTo, GLBObject mergeFrom) if (mergeFrom == null) throw new ArgumentNullException(nameof(mergeFrom)); // 1) merge json - // 2) copy mergefrom binary data to mergeto binary data - // 3) Fix up bufferviews to be the new offset + // 2) copy merge from binary data to merge to binary data + // 3) Fix up buffer views to be the new offset int previousBufferViewsCount = mergeTo.Root.BufferViews?.Count ?? 0; uint previousBufferSize = mergeTo.BinaryChunkInfo.Length; GLTFHelpers.MergeGLTF(mergeTo.Root, mergeFrom.Root); diff --git a/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs b/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs index 7d1832dbf..df6b25cf0 100644 --- a/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs +++ b/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs @@ -442,7 +442,7 @@ public static void BuildAnimationSamplers(ref Dictionary /// Merges the right root into the left root - /// This function combines all of the lists of objects on each glTF root together and updates the relative indicies + /// This function combines all of the lists of objects on each glTF root together and updates the relative indices /// All properties all merged except Asset and Default, which will stay "mergeToRoot"'s value /// /// The node to merge into @@ -475,7 +475,7 @@ public static void MergeGLTF(GLTFRoot mergeToRoot, GLTFRoot mergeFromRoot) // merge extensions MergeExtensions(mergeToRoot, mergeFromRootCopy); - // merge accessors, buffers, and bufferviews + // merge accessors, buffers, and buffer views MergeAccessorsBufferViewsAndBuffers(mergeToRoot, mergeFromRootCopy, previousGLTFSize); // merge materials, samplers, images, and textures diff --git a/Runtime/Plugins/GLTFSerialization/GLTFParser.cs b/Runtime/Plugins/GLTFSerialization/GLTFParser.cs index 93d7a5421..a5023f47c 100644 --- a/Runtime/Plugins/GLTFSerialization/GLTFParser.cs +++ b/Runtime/Plugins/GLTFSerialization/GLTFParser.cs @@ -135,7 +135,7 @@ public static List FindChunks(Stream stream, long startPosition = 0) ParseGLBHeader(stream); List allChunks = new List(); - // we only need to search for top two chunks (the JSON and binary chunks are guarenteed to be the top two chunks) + // we only need to search for top two chunks (the JSON and binary chunks are guaranteed to be the top two chunks) // other chunks can be in the file but we do not care about them for (int i = 0; i < 2; ++i) { diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/StreamExtensions.cs b/Runtime/Plugins/GLTFSerialization/Utilities/StreamExtensions.cs index 1a661ec24..f214ac3c7 100644 --- a/Runtime/Plugins/GLTFSerialization/Utilities/StreamExtensions.cs +++ b/Runtime/Plugins/GLTFSerialization/Utilities/StreamExtensions.cs @@ -40,7 +40,7 @@ public static void CopyTo(this Stream source, Stream destination) /// Size of array to use for each copy public static void CopyToSelf(this Stream source, int destinationOffset, uint amountToCopy) { - if (destinationOffset <= source.Position) throw new NotImplementedException("desintation offset must be larger than source offset"); + if (destinationOffset <= source.Position) throw new NotImplementedException("destination offset must be larger than source offset"); int highwaterMark = 0; long initialOffset = source.Position; diff --git a/Runtime/Scripts/GLTFSceneExporter.cs b/Runtime/Scripts/GLTFSceneExporter.cs index 67cfc843b..5747b4e5b 100644 --- a/Runtime/Scripts/GLTFSceneExporter.cs +++ b/Runtime/Scripts/GLTFSceneExporter.cs @@ -431,7 +431,7 @@ public struct ExportFileResult private const int GLTFHeaderSize = 12; private const int SectionHeaderSize = 8; - private bool _visbilityPluginEnabled = false; + private bool _visibilityPluginEnabled = false; public struct UniqueTexture : IEquatable { @@ -706,8 +706,8 @@ public GLTFSceneExporter(Transform[] rootTransforms, ExportContext context) _root.Asset.PluginExtras.Add(plugin.DisplayName, plugin.AssetExtras); } - _visbilityPluginEnabled = settings.ExportPlugins.Any(x => x is VisibilityExport && x.Enabled); - if (_visbilityPluginEnabled && !settings.ExportDisabledGameObjects) + _visibilityPluginEnabled = settings.ExportPlugins.Any(x => x is VisibilityExport && x.Enabled); + if (_visibilityPluginEnabled && !settings.ExportDisabledGameObjects) { Debug.Log(LogType.Warning,"KHR_node_visibility export plugin is enabled, but Export Disabled GameObjects is not. This may lead to unexpected results."); } @@ -988,14 +988,14 @@ private static string EnsureValidFileName(string filename) "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; - var sanitisedNamePart = Regex.Replace(filename, invalidReStr, "_"); + var sanitizedNamePart = Regex.Replace(filename, invalidReStr, "_"); foreach (var reservedWord in reservedWords) { var reservedWordPattern = string.Format("^{0}\\.", reservedWord); - sanitisedNamePart = Regex.Replace(sanitisedNamePart, reservedWordPattern, "_reservedWord_.", RegexOptions.IgnoreCase); + sanitizedNamePart = Regex.Replace(sanitizedNamePart, reservedWordPattern, "_reservedWord_.", RegexOptions.IgnoreCase); } - return sanitisedNamePart; + return sanitizedNamePart; } public void DeclareExtensionUsage(string extension, bool isRequired=false) @@ -1096,7 +1096,7 @@ private NodeId ExportNode(Transform nodeTransform) var node = new Node(); - if (_visbilityPluginEnabled && !nodeTransform.gameObject.activeSelf) + if (_visibilityPluginEnabled && !nodeTransform.gameObject.activeSelf) { DeclareExtensionUsage(KHR_node_visibility_Factory.EXTENSION_NAME, false); node.AddExtension(KHR_node_visibility_Factory.EXTENSION_NAME, new KHR_node_visibility { visible = false }); @@ -1110,7 +1110,7 @@ private NodeId ExportNode(Transform nodeTransform) // TODO think more about how this callback is used – could e.g. be modifying the hierarchy, // and we would want to prevent exporting children of this node. // Could also be that we want to add a mesh based on some condition - // (e.g. merged childs, procedural geometry, etc.) + // (e.g. merged children, procedural geometry, etc.) beforeNodeExportMarker.Begin(); foreach (var plugin in _plugins) plugin?.BeforeNodeExport(this, _root, nodeTransform, node); @@ -1205,41 +1205,41 @@ private NodeId ExportNode(Transform nodeTransform) // children that are not primitives get added as child nodes if (nonPrimitives.Length > 0) { - var parentOfChilds = node; + var parentOfChildren = node; // when we're exporting a light or camera, we add an implicit node as first child of the camera/light node. // this ensures that child objects and animations etc. "just work". if (needsInvertedLookDirection) { - var inbetween = new Node(); + var inBetween = new Node(); if (ExportNames) { - inbetween.Name = nodeTransform.name + "-flipped"; + inBetween.Name = nodeTransform.name + "-flipped"; } - inbetween.Rotation = Quaternion.Inverse(SchemaExtensions.InvertDirection).ToGltfQuaternionConvert(); + inBetween.Rotation = Quaternion.Inverse(SchemaExtensions.InvertDirection).ToGltfQuaternionConvert(); - var inbetweenId = new NodeId + var inBetweenId = new NodeId { Id = _root.Nodes.Count, Root = _root }; - _root.Nodes.Add(inbetween); + _root.Nodes.Add(inBetween); node.Children = new List(1); - node.Children.Add(inbetweenId); + node.Children.Add(inBetweenId); - parentOfChilds = inbetween; + parentOfChildren = inBetween; } - parentOfChilds.Children = new List(nonPrimitives.Length); + parentOfChildren.Children = new List(nonPrimitives.Length); foreach (var child in nonPrimitives) { if (!ShouldExportTransform(child.transform)) continue; var childNode = ExportNode(child.transform); - if (childNode != null) parentOfChilds.Children.Add(childNode); + if (childNode != null) parentOfChildren.Children.Add(childNode); } } diff --git a/Runtime/Scripts/GLTFSceneImporter.cs b/Runtime/Scripts/GLTFSceneImporter.cs index 09cdbb9c9..9bda4f367 100644 --- a/Runtime/Scripts/GLTFSceneImporter.cs +++ b/Runtime/Scripts/GLTFSceneImporter.cs @@ -1,4 +1,4 @@ -using GLTF; +using GLTF; using GLTF.Schema; using System; using System.Collections; @@ -134,7 +134,7 @@ public float Progress public override string ToString() { - return $"{(Progress * 100.0):F2}% (Buffers: {BuffersLoaded}/{BuffersTotal}, Nodes: {NodeLoaded}/{NodeTotal}, Texs: {TextureLoaded}/{TextureTotal})"; + return $"{(Progress * 100.0):F2}% (Buffers: {BuffersLoaded}/{BuffersTotal}, Nodes: {NodeLoaded}/{NodeTotal}, Textures: {TextureLoaded}/{TextureTotal})"; } } @@ -147,7 +147,7 @@ public struct ImportStatistics /// /// Converts gltf animation data to unity /// - public delegate float[] ValuesConvertion(NumericArray data, int frame); + public delegate float[] ValuesConversion(NumericArray data, int frame); public partial class GLTFSceneImporter : IDisposable { @@ -255,12 +255,12 @@ public GameObject LastLoadedScene /// /// Whether to keep a CPU-side copy of the texture after upload to GPU /// - /// + /// /// This is necessary when a texture is used with different sampler states, as Unity doesn't allow setting /// of filter and wrap modes separately form the texture object. Setting this to false will omit making a copy /// of a texture in that case and use the original texture's sampler state wherever it's referenced; this is /// appropriate in cases such as the filter and wrap modes being specified in the shader instead - /// + /// public bool KeepCPUCopyOfTexture = true; /// @@ -783,10 +783,10 @@ private void InitializeGltfTopLevelObject() if (_deduplicatedStatistics == null) _deduplicatedStatistics = new DeduplicatedStatistics(); - var meshfilters = CreatedObject.GetComponentsInChildren(); + var meshFilters = CreatedObject.GetComponentsInChildren(); var smr = CreatedObject.GetComponentsInChildren(); - var meshes = meshfilters.Select(m => m.sharedMesh).Concat(smr.Select(s => s.sharedMesh)).Distinct().ToArray(); + var meshes = meshFilters.Select(m => m.sharedMesh).Concat(smr.Select(s => s.sharedMesh)).Distinct().ToArray(); _deduplicatedStatistics.meshCountBefore = meshes.Length; var meshHashes = MeshHashUtility.ComputeMeshHashes(meshes); @@ -795,7 +795,7 @@ private void InitializeGltfTopLevelObject() var usedHashes = new List(); // Assign for each mesh-hash with group-count > 1, the first mesh of this hash-group - foreach (var m in meshfilters) + foreach (var m in meshFilters) { var hash = meshHashes[m.sharedMesh]; var hashGroup = groups[hash]; @@ -972,7 +972,7 @@ private async Task GetNode(int nodeId, CancellationToken cancellatio } catch (Exception ex) { - // If some failure occured during loading, remove the node + // If some failure occurred during loading, remove the node if (_assetCache.NodeCache[nodeId] != null) { @@ -1114,7 +1114,7 @@ protected virtual async Task ConstructNode(Node node, int nodeIndex, Cancellatio - async Task CreateNodeComponentsAndChilds(bool ignoreMesh = false, bool onlyMesh = false) + async Task CreateNodeComponentsAndChildren(bool ignoreMesh = false, bool onlyMesh = false) { // If we're creating a really large node, we need it to not be visible in partial stages. So we hide it while we create it nodeObj.SetActive(false); @@ -1206,20 +1206,20 @@ async Task CreateNodeComponentsAndChilds(bool ignoreMesh = false, bool onlyMesh // Cameras and lights have a different forward axis in glTF vs. Unity. // Thus, when importing lights and cameras we have to flip them. - // To ensure children are still oriented correctly, we need to add an inbetween node + // To ensure children are still oriented correctly, we need to add an in between node // That counters the transformation of the parent node. // This way, animations can still correctly apply – e.g. if a camera is animated, - // the childs should move along. We can't just add the camera to an empty child and flip that. + // the children should move along. We can't just add the camera to an empty child and flip that. if ((hasLight || hasCamera) && nodeObj.transform.childCount > 0 && node.Children?.Count > 0) { var flipQuaternion = Quaternion.Inverse(SchemaExtensions.InvertDirection); - // Special case for hierarchy simplification and roundtrips: if we have + // Special case for hierarchy simplification and round trips: if we have // - exactly one child // - that's flipped 180° // - and doesn't have any components // - and the node doesn't have any extensions - // we can just remove that, it's likely an inbetween our own exporter has added. + // we can just remove that, it's likely an in between our own exporter has added. // Theoretically, there are more conditions (not checked here): // - it's not targeted by any animations // - it's not the target of any glTF pointer or index @@ -1240,23 +1240,23 @@ async Task CreateNodeComponentsAndChilds(bool ignoreMesh = false, bool onlyMesh } UnityEngine.Object.DestroyImmediate(firstChild.gameObject); } - // Otherwise, we need to add an inbetween object + // Otherwise, we need to add an in between object else { var childCount = nodeObj.transform.childCount; - var inbetween = new GameObject(); - inbetween.name = node.Name + "-flipped"; + var inBetween = new GameObject(); + inBetween.name = node.Name + "-flipped"; // make sure this objects sits exactly where the nodeObj is - inbetween.transform.SetParent(nodeObj.transform, false); - inbetween.transform.SetParent(null, true); - // move all children to the inbetween object + inBetween.transform.SetParent(nodeObj.transform, false); + inBetween.transform.SetParent(null, true); + // move all children to the in between object for (int i = 0; i < childCount; i++) { // Index 0 is correct here, after removing the first child, the next one is now the first and we want to keep the order. - nodeObj.transform.GetChild(0).SetParent(inbetween.transform, true); + nodeObj.transform.GetChild(0).SetParent(inBetween.transform, true); } - inbetween.transform.SetParent(nodeObj.transform, true); - inbetween.transform.localRotation = Quaternion.Inverse(SchemaExtensions.InvertDirection); + inBetween.transform.SetParent(nodeObj.transform, true); + inBetween.transform.localRotation = Quaternion.Inverse(SchemaExtensions.InvertDirection); } } nodeObj.SetActive( ShouldBeVisible(node, nodeObj)); @@ -1266,12 +1266,12 @@ async Task CreateNodeComponentsAndChilds(bool ignoreMesh = false, bool onlyMesh if (instancesTRS == null || instancesTRS.Length == 0) { - await CreateNodeComponentsAndChilds(); + await CreateNodeComponentsAndChildren(); } else { var shouldBeVisible = ShouldBeVisible(node, nodeObj); - await CreateNodeComponentsAndChilds(true); + await CreateNodeComponentsAndChildren(true); var instanceParentNode = new GameObject("Instances"); instanceParentNode.transform.SetParent(nodeObj.transform, false); instanceParentNode.gameObject.SetActive(false); @@ -1282,7 +1282,7 @@ async Task CreateNodeComponentsAndChilds(bool ignoreMesh = false, bool onlyMesh { nodeObj = new GameObject(string.IsNullOrEmpty(node.Name) ? ("GLTFNode" + nodeIndex) : node.Name); nodeObj.transform.SetParent(instanceParentNode.transform, false); - await CreateNodeComponentsAndChilds(false, true); + await CreateNodeComponentsAndChildren(false, true); firstInstance = nodeObj; var renderers = firstInstance.GetComponentsInChildren(); @@ -1343,13 +1343,13 @@ protected async Task ConstructBuffer(GLTFBuffer buffer, int bufferIndex) { if (_assetCache.BufferCache[bufferIndex] != null) Debug.Log(LogType.Error, $"_assetCache.BufferCache[bufferIndex] != null; (File: {_gltfFileName})"); - var bufferCacheDate = new BufferCacheData + var bufferCacheData = new BufferCacheData { bufferData = new NativeArray((int)buffer.ByteLength, Allocator.Persistent), ChunkOffset = 0 }; - meshOptNativeBuffers.Add(bufferCacheDate.bufferData); + meshOptNativeBuffers.Add(bufferCacheData.bufferData); _assetCache.BufferCache[bufferIndex] = bufferCacheDate; return; } @@ -1509,7 +1509,7 @@ protected virtual async Task ConstructScene(GLTFScene scene, bool showSceneObj, } catch (Exception ex) { - // If some failure occured during loading, clean up the scene + // If some failure occurred during loading, clean up the scene UnityEngine.Object.DestroyImmediate(sceneObj); CreatedObject = null; diff --git a/Runtime/Scripts/GLTFSettings.cs b/Runtime/Scripts/GLTFSettings.cs index 50de3455c..470dfbb0f 100644 --- a/Runtime/Scripts/GLTFSettings.cs +++ b/Runtime/Scripts/GLTFSettings.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using UnityEngine; using System.IO; @@ -109,7 +109,7 @@ public enum TransformMode /** Reset local position, keep local rotation, keep world scale. This is a heuristic for exporting objects from anywhere in the scene for general usage. */ [InspectorName(("Auto: reset local position, keep local rotation, keep world scale"))] Auto, - /** Keep local position, rotation, and scale. This is useful if you want to export childs of hierarchies and import them again as childs. */ + /** Keep local position, rotation, and scale. This is useful if you want to export children of hierarchies and import them again as childs. */ [InspectorName("Local: keep local position, rotation and scale")] LocalTransforms, /** Keep world position, rotation, and scale. This is useful for exporting parts of scenes and keeping all relations between objects the same. */ diff --git a/Runtime/Scripts/SceneExporter/ExporterAccessors.cs b/Runtime/Scripts/SceneExporter/ExporterAccessors.cs index 09260f5a2..d70db01aa 100644 --- a/Runtime/Scripts/SceneExporter/ExporterAccessors.cs +++ b/Runtime/Scripts/SceneExporter/ExporterAccessors.cs @@ -55,7 +55,7 @@ private static void AlignToBoundary(Stream stream, byte pad = (byte)' ', uint bo /// /// Calculates the number of bytes of padding required to align the - /// size of a buffer with some multiple of byteAllignment. + /// size of a buffer with some multiple of byteAlignment. /// /// The current size of the buffer. /// The number of bytes to align with. @@ -254,10 +254,10 @@ private AccessorId ExportAccessorSwitchHandedness(Quaternion[] arr, bool invertL #else foreach (var vec in arr) { - _bufferWriter.Write(vect.x); - _bufferWriter.Write(vect.y); - _bufferWriter.Write(vect.z); - _bufferWriter.Write(vect.w); + _bufferWriter.Write(vec.x); + _bufferWriter.Write(vec.y); + _bufferWriter.Write(vec.z); + _bufferWriter.Write(vec.w); } #endif exportAccessorBufferWriteMarker.End(); @@ -799,7 +799,7 @@ private AccessorId ExportAccessor(Vector3[] arr) /// /// /// - /// The data is treated as "additive" (e.g. blendshapes) when baseData != null + /// The data is treated as "additive" (e.g. blend shapes) when baseData != null /// /// /// diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index 84617824a..d9a799492 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -103,7 +103,7 @@ protected void SetAnimationCurve( NumericArray output, InterpolationType mode, Type curveType, - ValuesConvertion getConvertedValues) + ValuesConversion getConvertedValues) { var channelCount = propertyNames.Length; var frameCount = input.AsFloats.Length; diff --git a/Runtime/Scripts/SceneImporter/ImporterMeshes.cs b/Runtime/Scripts/SceneImporter/ImporterMeshes.cs index 4ca546240..7492307d2 100644 --- a/Runtime/Scripts/SceneImporter/ImporterMeshes.cs +++ b/Runtime/Scripts/SceneImporter/ImporterMeshes.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -540,8 +540,8 @@ protected async Task ConstructUnityMesh(GLTFMesh gltfMesh, DecodeResult[] decode bonesPerVertexCount += subMeshes[i].GetBonesPerVertex().Length; } - // Custom combine all boneweights and bonePerVertex of sub meshes and apply to final combined mesh - // >> Bug(?) in CombineMeshes that does not proper copy bone weights and bones per vertex + // Custom combine all bone weights and bonePerVertex of sub meshes and apply to final combined mesh + // >> Bug(?) in CombineMeshes that does not proper copy bone weights and bones per vertex NativeArray allBoneWeights = new NativeArray(boneWeightCount, Allocator.TempJob); NativeArray allBonesPerVertex = new NativeArray(bonesPerVertexCount, Allocator.TempJob); int currentArrayPositionBoneWeights = 0; @@ -1082,7 +1082,7 @@ private async Task PreparePrimitiveAttributes() var gltfMesh = _gltfRoot.Meshes[meshIndex]; var meshHash = gltfMesh.GetHashFromPrimitiveAttributes(); - // When we allready decoded a mesh with the same attribute layout, we can reuse the draco decode results and skip decoding this mesh + // When we already decoded a mesh with the same attribute layout, we can reuse the draco decode results and skip decoding this mesh if (dracoMeshAttrHashes.TryGetValue(meshHash, out var existingDracoResult)) { var resultCopy = new DracoDecodeResult(); @@ -1182,7 +1182,7 @@ private async Task ConstructMeshAttributes(GLTFMesh mesh, MeshId meshId) if (primitive.Targets != null) { - // read mesh primitive targets into assetcache + // read mesh primitive targets into asset cache await ConstructMeshTargetsPrepareBuffers(primitive, meshIndex, i); ConstructMeshTargets(primitive, meshIndex, i); } diff --git a/Runtime/Scripts/SceneImporter/ImporterSkinning.cs b/Runtime/Scripts/SceneImporter/ImporterSkinning.cs index 5e0fea2f3..17eede369 100644 --- a/Runtime/Scripts/SceneImporter/ImporterSkinning.cs +++ b/Runtime/Scripts/SceneImporter/ImporterSkinning.cs @@ -19,7 +19,7 @@ protected virtual async Task SetupBones(Skin skin, SkinnedMeshRenderer renderer, var boneCount = skin.Joints.Count; Transform[] bones = new Transform[boneCount]; - // TODO: build bindpose arrays only once per skin, instead of once per node + // TODO: build bind pose arrays only once per skin, instead of once per node float4x4[] gltfBindPoses = null; if (skin.InverseBindMatrices != null) { From 5ad866c03036c863068905ffbd462c81a2603499 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Tue, 23 Jun 2026 00:49:11 -0700 Subject: [PATCH 2/5] Rename and relocate several things for clarity --- .../Plugins/GLTFSerialization/GLBBuilder.cs | 90 +++++++++---------- .../Plugins/GLTFSerialization/GLBObject.cs | 41 ++++++++- .../Plugins/GLTFSerialization/GLTFParser.cs | 83 ++++++----------- Runtime/Scripts/Cache/BufferCacheData.cs | 5 +- Runtime/Scripts/GLTFSceneExporter.cs | 3 +- Runtime/Scripts/GLTFSceneImporter.cs | 12 +-- .../SceneImporter/ImporterAnimation.cs | 4 +- .../Scripts/SceneImporter/ImporterMeshes.cs | 18 ++-- .../Scripts/SceneImporter/ImporterSkinning.cs | 2 +- .../Scripts/SceneImporter/ImporterTextures.cs | 6 +- 10 files changed, 135 insertions(+), 129 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs index 4ff227df1..de5bcc13c 100644 --- a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs +++ b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs @@ -27,12 +27,12 @@ private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, F root.Serialize(sw, true); sw.Flush(); - long proposedLength = gltfJsonStream.Length + GLTFParser.HEADER_SIZE + GLTFParser.CHUNK_HEADER_SIZE; + long proposedFileLength = gltfJsonStream.Length + GLBHeader.GLB2_FILE_HEADER_SIZE + GLBHeader.GLB2_CHUNK_HEADER_SIZE; if (gltfJsonStream.Length > uint.MaxValue) { throw new ArgumentException("Serialized root cannot exceed uint.MaxValue", nameof(root)); } - uint proposedLengthAsUint = (uint)proposedLength; + uint proposedLengthAsUint = (uint)proposedFileLength; glbOutStream.SetLength(proposedLengthAsUint); GLBObject glbObject = new GLBObject { @@ -43,11 +43,11 @@ private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, F }, Root = root, Stream = glbOutStream, - JsonChunkInfo = new ChunkInfo + JsonChunkInfo = new GLBChunkInfo { Length = (uint)gltfJsonStream.Length, - StartPosition = GLTFParser.HEADER_SIZE, - Type = ChunkFormat.JSON + StartPosition = GLBHeader.GLB2_FILE_HEADER_SIZE, + Type = GLBChunkFormat.JSON } }; @@ -89,27 +89,27 @@ public static GLBObject ConstructFromGLB(GLTFRoot root, Stream inputGLBStream, S // header information is 4 bytes in, past the magic number inputGLBStream.Position = 4 + inputGLBStreamStartPosition; - GLBHeader header = GLTFParser.ParseGLBHeader(inputGLBStream); + GLBHeader glbHeader = GLTFParser.ParseGLBHeader(inputGLBStream); - inputGLBStream.Position = GLTFParser.HEADER_SIZE + inputGLBStreamStartPosition; - List allChunks = GLTFParser.FindChunks(inputGLBStream); - ChunkInfo jsonChunkInfo = new ChunkInfo + inputGLBStream.Position = GLBHeader.GLB2_FILE_HEADER_SIZE + inputGLBStreamStartPosition; + List allChunks = GLTFParser.FindChunks(inputGLBStream); + GLBChunkInfo jsonChunkInfo = new GLBChunkInfo { - Type = ChunkFormat.JSON + Type = GLBChunkFormat.JSON }; - ChunkInfo binaryChunkInfo = new ChunkInfo + GLBChunkInfo binaryChunkInfo = new GLBChunkInfo { - Type = ChunkFormat.BIN + Type = GLBChunkFormat.BIN }; - foreach (ChunkInfo chunkInfo in allChunks) + foreach (GLBChunkInfo chunkInfo in allChunks) { switch (chunkInfo.Type) { - case ChunkFormat.JSON: + case GLBChunkFormat.JSON: jsonChunkInfo = chunkInfo; break; - case ChunkFormat.BIN: + case GLBChunkFormat.BIN: binaryChunkInfo = chunkInfo; break; } @@ -126,7 +126,7 @@ public static GLBObject ConstructFromGLB(GLTFRoot root, Stream inputGLBStream, S Root = root, Stream = outStream, StreamStartPosition = inputGLBStreamStartPosition, - Header = header, + Header = glbHeader, JsonChunkInfo = jsonChunkInfo, BinaryChunkInfo = binaryChunkInfo }; @@ -170,21 +170,21 @@ private static GLBObject _ConstructFromEmptyStream(Stream inStream, long streamS GLBObject glbObject = new GLBObject { Stream = inStream, - JsonChunkInfo = new ChunkInfo + JsonChunkInfo = new GLBChunkInfo { Length = 0, - StartPosition = GLTFParser.HEADER_SIZE, - Type = ChunkFormat.JSON + StartPosition = GLBHeader.GLB2_FILE_HEADER_SIZE, + Type = GLBChunkFormat.JSON }, - BinaryChunkInfo = new ChunkInfo + BinaryChunkInfo = new GLBChunkInfo { Length = 0, - StartPosition = GLTFParser.HEADER_SIZE + GLTFParser.CHUNK_HEADER_SIZE, - Type = ChunkFormat.BIN + StartPosition = GLBHeader.GLB2_FILE_HEADER_SIZE + GLBHeader.GLB2_CHUNK_HEADER_SIZE, + Type = GLBChunkFormat.BIN }, Header = new GLBHeader { - FileLength = GLTFParser.HEADER_SIZE, + FileLength = GLBHeader.GLB2_FILE_HEADER_SIZE, Version = 2 }, StreamStartPosition = streamStartPosition @@ -229,22 +229,22 @@ public static void UpdateStream(GLBObject glb) // we have not yet initialized a json chunk before if (glb.JsonChunkInfo.Length == 0) { - amountToAddToFile += GLTFParser.CHUNK_HEADER_SIZE; - glb.SetJsonChunkStartPosition(GLTFParser.HEADER_SIZE); + amountToAddToFile += GLBHeader.GLB2_CHUNK_HEADER_SIZE; + glb.SetJsonChunkStartPosition(GLBHeader.GLB2_FILE_HEADER_SIZE); } // new proposed length = proposedJsonBufferSize - currentJsonBufferSize + totalFileLength - long proposedLength = amountToAddToFile + glb.Header.FileLength; - if (proposedLength > uint.MaxValue) + long proposedFileLength = amountToAddToFile + glb.Header.FileLength; + if (proposedFileLength > uint.MaxValue) { throw new Exception("GLB has exceeded max allowed size (4 GB)"); } - uint proposedLengthAsUint = (uint)proposedLength; + uint proposedLengthAsUint = (uint)proposedFileLength; try { - glb.Stream.SetLength(proposedLength); + glb.Stream.SetLength(proposedFileLength); } catch (IOException e) { @@ -256,17 +256,17 @@ public static void UpdateStream(GLBObject glb) throw; } - long newBinaryChunkStartPosition = - GLTFParser.HEADER_SIZE + GLTFParser.CHUNK_HEADER_SIZE + proposedJsonChunkLength; + long newBinaryChunkDataStartPosition = + GLBHeader.GLB2_FILE_HEADER_SIZE + GLBHeader.GLB2_CHUNK_HEADER_SIZE + proposedJsonChunkLength; glb.Stream.Position = glb.BinaryChunkInfo.StartPosition; - glb.SetBinaryChunkStartPosition(newBinaryChunkStartPosition); + glb.SetBinaryChunkStartPosition(newBinaryChunkDataStartPosition); if (glb.BinaryChunkInfo.Length > 0) { - uint lengthToCopy = glb.BinaryChunkInfo.Length + GLTFParser.CHUNK_HEADER_SIZE; + uint lengthToCopy = glb.BinaryChunkInfo.Length + GLBHeader.GLB2_CHUNK_HEADER_SIZE; // todo: we need to be able to copy while doing it with smaller buffers. Also int is smaller than uint, so this is not standards compliant. - glb.Stream.CopyToSelf((int)newBinaryChunkStartPosition, + glb.Stream.CopyToSelf((int)newBinaryChunkDataStartPosition, lengthToCopy); } @@ -280,7 +280,7 @@ public static void UpdateStream(GLBObject glb) } // clear the buffer - glb.Stream.Position = glb.JsonChunkInfo.StartPosition + GLTFParser.CHUNK_HEADER_SIZE; + glb.Stream.Position = glb.JsonChunkInfo.StartPosition + GLBHeader.GLB2_CHUNK_HEADER_SIZE; uint amountToCopy = glb.JsonChunkInfo.Length; while (amountToCopy != 0) { @@ -293,7 +293,7 @@ public static void UpdateStream(GLBObject glb) // write new JSON data gltfJsonStream.Position = 0; - glb.Stream.Position = glb.JsonChunkInfo.StartPosition + GLTFParser.CHUNK_HEADER_SIZE; + glb.Stream.Position = glb.JsonChunkInfo.StartPosition + GLBHeader.GLB2_CHUNK_HEADER_SIZE; gltfJsonStream.CopyTo(glb.Stream); glb.Stream.Flush(); } @@ -332,8 +332,8 @@ private static BufferViewId _AddBinaryData(GLBObject glb, Stream binaryData, boo // there was an existing file that had no binary chunk info previously if (glb.BinaryChunkInfo.Length == 0) { - newGLBSize += GLTFParser.CHUNK_HEADER_SIZE; - blobWritePosition += GLTFParser.CHUNK_HEADER_SIZE; + newGLBSize += GLBHeader.GLB2_CHUNK_HEADER_SIZE; + blobWritePosition += GLBHeader.GLB2_CHUNK_HEADER_SIZE; glb.SetBinaryChunkStartPosition(glb.Header.FileLength); // if 0, then appends chunk info at the end } @@ -397,7 +397,7 @@ public static void MergeGLBs(GLBObject mergeTo, GLBObject mergeFrom) int previousBufferViewsCount = mergeTo.Root.BufferViews?.Count ?? 0; uint previousBufferSize = mergeTo.BinaryChunkInfo.Length; GLTFHelpers.MergeGLTF(mergeTo.Root, mergeFrom.Root); - _AddBinaryData(mergeTo, mergeFrom.Stream, false, mergeFrom.BinaryChunkInfo.StartPosition + GLTFParser.CHUNK_HEADER_SIZE); + _AddBinaryData(mergeTo, mergeFrom.Stream, false, mergeFrom.BinaryChunkInfo.StartPosition + GLBHeader.GLB2_CHUNK_HEADER_SIZE); uint bufferSizeDiff = mergeTo.BinaryChunkInfo.Length - previousBufferSize; // calculate buffer size change to update the byte offsets of the appended buffer views @@ -438,7 +438,7 @@ public static void RemoveBinaryData(GLBObject glb, BufferViewId bufferViewId) --bufferView.Buffer.Id; } - glb.SetFileLength(glb.Header.FileLength - GLTFParser.CHUNK_HEADER_SIZE); + glb.SetFileLength(glb.Header.FileLength - GLBHeader.GLB2_CHUNK_HEADER_SIZE); } else { @@ -505,19 +505,19 @@ public static void SetRoot(GLBObject glb, GLTFRoot newRoot) } } - private static void WriteHeader(Stream stream, GLBHeader header, long streamStartPosition) + private static void WriteHeader(Stream stream, GLBHeader glbHeader, long streamStartPosition) { stream.Position = streamStartPosition; - byte[] magicNumber = BitConverter.GetBytes(GLTFParser.MAGIC_NUMBER); - byte[] version = BitConverter.GetBytes(header.Version); - byte[] length = BitConverter.GetBytes(header.FileLength); + byte[] magicNumber = BitConverter.GetBytes(GLBHeader.GLTF_MAGIC_NUMBER); + byte[] version = BitConverter.GetBytes(glbHeader.Version); + byte[] length = BitConverter.GetBytes(glbHeader.FileLength); stream.Write(magicNumber, 0, magicNumber.Length); stream.Write(version, 0, version.Length); stream.Write(length, 0, length.Length); } - private static void WriteChunkHeader(Stream stream, ChunkInfo chunkInfo) + private static void WriteChunkHeader(Stream stream, GLBChunkInfo chunkInfo) { stream.Position = chunkInfo.StartPosition; byte[] lengthBytes = BitConverter.GetBytes(chunkInfo.Length); diff --git a/Runtime/Plugins/GLTFSerialization/GLBObject.cs b/Runtime/Plugins/GLTFSerialization/GLBObject.cs index e89f0317e..2196ac101 100644 --- a/Runtime/Plugins/GLTFSerialization/GLBObject.cs +++ b/Runtime/Plugins/GLTFSerialization/GLBObject.cs @@ -4,6 +4,39 @@ namespace GLTF { + public enum GLBChunkFormat : uint + { + JSON = 0x4e4f534a, // ASCII string "JSON" in little-endian order. + BIN = 0x004e4942 // ASCII string "BIN\0" in little-endian order. + } + + /// + /// Information containing parsed GLB Header + /// + public struct GLBHeader + { + public uint Version { get; set; } + public uint FileLength { get; set; } + + public static readonly uint GLB2_FILE_HEADER_SIZE = 12; + public static readonly uint GLB2_CHUNK_HEADER_SIZE = 8; + + /// + /// ASCII string "glTF" in little-endian order. + /// + public static readonly uint GLTF_MAGIC_NUMBER = 0x46546C67; + } + + /// + /// Information that contains parsed chunk + /// + public struct GLBChunkInfo + { + public long StartPosition; + public uint Length; + public GLBChunkFormat Type; + } + /// /// Objects containing GLB data and associated parsing information /// @@ -41,16 +74,16 @@ public GLBObject(GLBObject other) /// /// Information on JSON chunk /// - public ChunkInfo JsonChunkInfo { get { return _jsonChunkInfo; } internal set { _jsonChunkInfo = value; } } + public GLBChunkInfo JsonChunkInfo { get { return _jsonChunkInfo; } internal set { _jsonChunkInfo = value; } } /// /// Information on Binary chunk /// - public ChunkInfo BinaryChunkInfo { get { return _binaryChunkInfo; } internal set { _binaryChunkInfo = value; } } + public GLBChunkInfo BinaryChunkInfo { get { return _binaryChunkInfo; } internal set { _binaryChunkInfo = value; } } private GLBHeader _glbHeader; - private ChunkInfo _jsonChunkInfo; - private ChunkInfo _binaryChunkInfo; + private GLBChunkInfo _jsonChunkInfo; + private GLBChunkInfo _binaryChunkInfo; internal GLBObject() { diff --git a/Runtime/Plugins/GLTFSerialization/GLTFParser.cs b/Runtime/Plugins/GLTFSerialization/GLTFParser.cs index a5023f47c..00f7009f4 100644 --- a/Runtime/Plugins/GLTFSerialization/GLTFParser.cs +++ b/Runtime/Plugins/GLTFSerialization/GLTFParser.cs @@ -5,37 +5,8 @@ namespace GLTF { - public enum ChunkFormat : uint - { - JSON = 0x4e4f534a, - BIN = 0x004e4942 - } - - /// - /// Information containing parsed GLB Header - /// - public struct GLBHeader - { - public uint Version { get; set; } - public uint FileLength { get; set; } - } - - /// - /// Infomration that contains parsed chunk - /// - public struct ChunkInfo - { - public long StartPosition; - public uint Length; - public ChunkFormat Type; - } - public class GLTFParser { - public static readonly uint HEADER_SIZE = 12; - public static readonly uint CHUNK_HEADER_SIZE = 8; - public static readonly uint MAGIC_NUMBER = 0x46546c67; - public static void ParseJson(Stream stream, out GLTFRoot gltfRoot, long startPosition = 0) { stream.Position = startPosition; @@ -44,7 +15,7 @@ public static void ParseJson(Stream stream, out GLTFRoot gltfRoot, long startPos // Check for binary format magic bytes if (isGLB) { - ParseJsonChunk(stream, startPosition); + ParseJsonChunkAndFileHeader(stream, startPosition); } else { @@ -57,10 +28,10 @@ public static void ParseJson(Stream stream, out GLTFRoot gltfRoot, long startPos // todo: this needs reimplemented. There is no such thing as a binary chunk index, and the chunk may not be in 0, 1, 2 order // Moves stream position to binary chunk location - public static ChunkInfo SeekToBinaryChunk(Stream stream, int binaryChunkIndex, long startPosition = 0) + public static GLBChunkInfo SeekToBinaryChunkData(Stream stream, int binaryChunkIndex, long startPosition = 0) { - stream.Position = startPosition + 4; // start after magic number chunk - GLBHeader header = ParseGLBHeader(stream); + stream.Position = startPosition + 4; // Start after "glTF" magic number. + GLBHeader glbHeader = ParseGLBHeader(stream); uint chunkOffset = 12; // sizeof(GLBHeader) + magic number uint chunkLength = 0; for (int i = 0; i < binaryChunkIndex + 2; ++i) @@ -72,17 +43,17 @@ public static ChunkInfo SeekToBinaryChunk(Stream stream, int binaryChunkIndex, l } // Load Binary Chunk - if (chunkOffset + chunkLength <= header.FileLength) + if (chunkOffset + chunkLength <= glbHeader.FileLength) { - ChunkFormat chunkType = (ChunkFormat)GetUInt32(stream); - if (chunkType != ChunkFormat.BIN) + GLBChunkFormat chunkType = (GLBChunkFormat)GetUInt32(stream); + if (chunkType != GLBChunkFormat.BIN) { throw new GLTFHeaderInvalidException("Second chunk must be of type BIN if present"); } - return new ChunkInfo + return new GLBChunkInfo { - StartPosition = stream.Position - CHUNK_HEADER_SIZE, + StartPosition = stream.Position - GLBHeader.GLB2_CHUNK_HEADER_SIZE, Length = chunkLength, Type = chunkType }; @@ -92,11 +63,11 @@ public static ChunkInfo SeekToBinaryChunk(Stream stream, int binaryChunkIndex, l // Be aware that File length does not match header when MeshOpt compression is used! //throw new GLTFHeaderInvalidException("File length does not match chunk header."); - return new ChunkInfo + return new GLBChunkInfo { - StartPosition = stream.Position - CHUNK_HEADER_SIZE, + StartPosition = stream.Position - GLBHeader.GLB2_CHUNK_HEADER_SIZE, Length = chunkLength, - Type = ChunkFormat.BIN + Type = GLBChunkFormat.BIN }; } @@ -114,26 +85,26 @@ public static GLBHeader ParseGLBHeader(Stream stream) public static bool IsGLB(Stream stream) { - return GetUInt32(stream) == 0x46546c67; // 0 + return GetUInt32(stream) == GLBHeader.GLTF_MAGIC_NUMBER; } - public static ChunkInfo ParseChunkInfo(Stream stream) + public static GLBChunkInfo ParseChunkInfo(Stream stream) { - ChunkInfo chunkInfo = new ChunkInfo + GLBChunkInfo chunkInfo = new GLBChunkInfo { StartPosition = stream.Position }; chunkInfo.Length = GetUInt32(stream); // 12 - chunkInfo.Type = (ChunkFormat)GetUInt32(stream); // 16 + chunkInfo.Type = (GLBChunkFormat)GetUInt32(stream); // 16 return chunkInfo; } - public static List FindChunks(Stream stream, long startPosition = 0) + public static List FindChunks(Stream stream, long startPosition = 0) { - stream.Position = startPosition + 4; // start after magic number bytes (4 bytes past) + stream.Position = startPosition + 4; // Start after "glTF" magic number. ParseGLBHeader(stream); - List allChunks = new List(); + List allChunks = new List(); // we only need to search for top two chunks (the JSON and binary chunks are guaranteed to be the top two chunks) // other chunks can be in the file but we do not care about them @@ -144,7 +115,7 @@ public static List FindChunks(Stream stream, long startPosition = 0) break; } - ChunkInfo chunkInfo = ParseChunkInfo(stream); + GLBChunkInfo chunkInfo = ParseChunkInfo(stream); allChunks.Add(chunkInfo); stream.Position += chunkInfo.Length; } @@ -152,21 +123,21 @@ public static List FindChunks(Stream stream, long startPosition = 0) return allChunks; } - private static void ParseJsonChunk(Stream stream, long startPosition) + private static void ParseJsonChunkAndFileHeader(Stream stream, long startPosition) { - GLBHeader header = ParseGLBHeader(stream); // 4, 8 - if (header.Version != 2) + GLBHeader glbHeader = ParseGLBHeader(stream); // 4, 8 + if (glbHeader.Version != 2) { throw new GLTFHeaderInvalidException("Unsupported glTF version"); }; - if (header.FileLength > (stream.Length - startPosition)) + if (glbHeader.FileLength > (stream.Length - startPosition)) { - throw new GLTFHeaderInvalidException("File length does not match header."); + throw new GLTFHeaderInvalidException("File length does not match GLB file header declared length."); } - ChunkInfo chunkInfo = ParseChunkInfo(stream); - if (chunkInfo.Type != ChunkFormat.JSON) + GLBChunkInfo chunkInfo = ParseChunkInfo(stream); + if (chunkInfo.Type != GLBChunkFormat.JSON) { throw new GLTFHeaderInvalidException("First chunk must be of type JSON"); } diff --git a/Runtime/Scripts/Cache/BufferCacheData.cs b/Runtime/Scripts/Cache/BufferCacheData.cs index f43d8b9f6..2147ee02d 100644 --- a/Runtime/Scripts/Cache/BufferCacheData.cs +++ b/Runtime/Scripts/Cache/BufferCacheData.cs @@ -5,7 +5,10 @@ namespace UnityGLTF.Cache { public class BufferCacheData : IDisposable { - public uint ChunkOffset { get; set; } + /// + /// The offset in the stream where the chunk data starts, past the chunk header. + /// + public uint ChunkDataOffset { get; set; } public System.IO.Stream Stream { get; set; } public NativeArray bufferData { get; set; } diff --git a/Runtime/Scripts/GLTFSceneExporter.cs b/Runtime/Scripts/GLTFSceneExporter.cs index 5747b4e5b..e115f972a 100644 --- a/Runtime/Scripts/GLTFSceneExporter.cs +++ b/Runtime/Scripts/GLTFSceneExporter.cs @@ -424,7 +424,6 @@ public struct ExportFileResult private Material _normalChannelMaterial; - private const uint MagicGLTF = 0x46546C67; private const uint Version = 2; private const uint MagicJson = 0x4E4F534A; private const uint MagicBin = 0x004E4942; @@ -827,7 +826,7 @@ public void SaveGLBToStream(Stream stream, string sceneName) BinaryWriter writer = new BinaryWriter(stream); // write header - writer.Write(MagicGLTF); + writer.Write(GLTF.GLBHeader.GLTF_MAGIC_NUMBER); writer.Write(Version); writer.Write(glbLength); diff --git a/Runtime/Scripts/GLTFSceneImporter.cs b/Runtime/Scripts/GLTFSceneImporter.cs index 9bda4f367..70fc5ddc9 100644 --- a/Runtime/Scripts/GLTFSceneImporter.cs +++ b/Runtime/Scripts/GLTFSceneImporter.cs @@ -893,7 +893,7 @@ private void GetGltfContentTotals(GLTFScene scene) public NativeArray GetBufferViewData(BufferView bufferView) { GetBufferData(bufferView.Buffer).Wait(); - GLTFHelpers.LoadBufferView(bufferView, _assetCache.BufferCache[bufferView.Buffer.Id].ChunkOffset, _assetCache.BufferCache[bufferView.Buffer.Id].bufferData, out var bufferViewCache); + GLTFHelpers.LoadBufferView(bufferView, _assetCache.BufferCache[bufferView.Buffer.Id].ChunkDataOffset, _assetCache.BufferCache[bufferView.Buffer.Id].bufferData, out var bufferViewCache); return bufferViewCache; } @@ -1013,7 +1013,7 @@ async Task GetAttrAccessorAndAccessorContent(AccessorId acces { AccessorId = accessorId, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkOffset + Offset = (uint)bufferData.ChunkDataOffset }; GLTFHelpers.LoadBufferView(accessor.BufferView.Value, attrAccessor.Offset, attrAccessor.bufferData, out var bufferViewCache); NumericArray resultArray = attrAccessor.AccessorContent; @@ -1346,11 +1346,11 @@ protected async Task ConstructBuffer(GLTFBuffer buffer, int bufferIndex) var bufferCacheData = new BufferCacheData { bufferData = new NativeArray((int)buffer.ByteLength, Allocator.Persistent), - ChunkOffset = 0 + ChunkDataOffset = 0 }; meshOptNativeBuffers.Add(bufferCacheData.bufferData); - _assetCache.BufferCache[bufferIndex] = bufferCacheDate; + _assetCache.BufferCache[bufferIndex] = bufferCacheData; return; } #else @@ -1527,11 +1527,11 @@ protected virtual async Task ConstructScene(GLTFScene scene, bool showSceneObj, protected virtual BufferCacheData ConstructBufferFromGLB(int bufferIndex) { - GLTFParser.SeekToBinaryChunk(_gltfStream.Stream, bufferIndex, _gltfStream.StartPosition); // sets stream to correct start position + GLTFParser.SeekToBinaryChunkData(_gltfStream.Stream, bufferIndex, _gltfStream.StartPosition); // sets stream to correct start position return new BufferCacheData { Stream = _gltfStream.Stream, - ChunkOffset = (uint)_gltfStream.Stream.Position, + ChunkDataOffset = (uint)_gltfStream.Stream.Position, bufferData = GetOrCreateNativeBuffer(_gltfStream.Stream), }; } diff --git a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs index d9a799492..f9526cf81 100644 --- a/Runtime/Scripts/SceneImporter/ImporterAnimation.cs +++ b/Runtime/Scripts/SceneImporter/ImporterAnimation.cs @@ -66,7 +66,7 @@ protected virtual async Task BuildAnimationSamplers(GLTFAnimation animation, int { AccessorId = samplerDef.Input, bufferData = inputBufferCacheData?.bufferData ?? default, - Offset = inputBufferCacheData?.ChunkOffset ?? 0, + Offset = inputBufferCacheData?.ChunkDataOffset ?? 0, }; samplers[i].Input = attributeAccessor; @@ -78,7 +78,7 @@ protected virtual async Task BuildAnimationSamplers(GLTFAnimation animation, int { AccessorId = samplerDef.Output, bufferData = outputBufferCacheData?.bufferData ?? default, - Offset = outputBufferCacheData?.ChunkOffset ?? 0, + Offset = outputBufferCacheData?.ChunkDataOffset ?? 0, }; samplers[i].Output = attributeAccessor; diff --git a/Runtime/Scripts/SceneImporter/ImporterMeshes.cs b/Runtime/Scripts/SceneImporter/ImporterMeshes.cs index 7492307d2..0d6f34a98 100644 --- a/Runtime/Scripts/SceneImporter/ImporterMeshes.cs +++ b/Runtime/Scripts/SceneImporter/ImporterMeshes.cs @@ -292,7 +292,7 @@ protected virtual DracoDecodeResult ConstructDracoMesh(GLTFMesh mesh, int meshIn BufferCacheData bufferContents = _assetCache.BufferCache[dracoExtension.bufferView.Value.Buffer.Id]; - GLTFHelpers.LoadBufferView(dracoExtension.bufferView.Value, bufferContents.ChunkOffset, + GLTFHelpers.LoadBufferView(dracoExtension.bufferView.Value, bufferContents.ChunkDataOffset, bufferContents.bufferData, out NativeArray bufferViewData); int weightsAttributeId = -1; @@ -399,7 +399,7 @@ private async Task MeshOptDecodeBuffer(GLTFRoot root) BufferCacheData bufferContents = _assetCache.BufferCache[meshOpt.bufferView.Buffer.Id]; - GLTFHelpers.LoadBufferView(meshOpt.bufferView, bufferContents.ChunkOffset, bufferContents.bufferData, out NativeArray bufferViewData); + GLTFHelpers.LoadBufferView(meshOpt.bufferView, bufferContents.ChunkDataOffset, bufferContents.bufferData, out NativeArray bufferViewData); #if HAVE_MESHOPT_DECOMPRESS_VERSION_0_2 var jobHandle = Meshoptimizer.Decode.DecodeGltfBuffer(meshOptReturnValues.GetSubArray(bufferViewIndex, 1), @@ -850,7 +850,7 @@ protected virtual async Task ConstructMeshTargetsPrepareBuffers(MeshPrimitive pr { AccessorId = targetAttribute.Value, bufferData = _assetCache.BufferCache[bufferID].bufferData, - Offset = (uint)_assetCache.BufferCache[bufferID].ChunkOffset + Offset = (uint)_assetCache.BufferCache[bufferID].ChunkDataOffset }; // if this buffer isn't sparse, we're done here @@ -910,7 +910,7 @@ protected virtual void ConstructMeshTargets(MeshPrimitive primitive, int meshInd { AccessorId = targetAttribute.Value, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkOffset + Offset = (uint)bufferData.ChunkDataOffset }; GLTFHelpers.LoadBufferView(sparseValues.AccessorId.Value.Sparse.Values.BufferView.Value, sparseValues.Offset, sparseValues.bufferData, out NativeArray bufferViewCache1); @@ -922,7 +922,7 @@ protected virtual void ConstructMeshTargets(MeshPrimitive primitive, int meshInd { AccessorId = targetAttribute.Value, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkOffset, + Offset = (uint)bufferData.ChunkDataOffset, }; GLTFHelpers.LoadBufferView(sparseIndices.AccessorId.Value.Sparse.Indices.BufferView.Value, sparseIndices.Offset, sparseIndices.bufferData, out NativeArray bufferViewCache2); @@ -1218,7 +1218,7 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv { AccessorId = attributePair.Value, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkOffset + Offset = (uint)bufferData.ChunkDataOffset }; } @@ -1233,7 +1233,7 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv { AccessorId = attributePair.Value, bufferData = sparseBufferData.bufferData, - Offset = (uint)sparseBufferData.ChunkOffset + Offset = (uint)sparseBufferData.ChunkDataOffset }; var sparseIndicesBufferId = sparse.Indices.BufferView.Value.Buffer; @@ -1242,7 +1242,7 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv { AccessorId = attributePair.Value, bufferData = sparseIndicesBufferData.bufferData, - Offset = (uint)sparseIndicesBufferData.ChunkOffset + Offset = (uint)sparseIndicesBufferData.ChunkDataOffset }; primData.SparseAccessors[attributePair.Key] = (sparseIndices, sparseValues); @@ -1261,7 +1261,7 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv { AccessorId = primitive.Indices, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkOffset + Offset = (uint)bufferData.ChunkDataOffset }; } } diff --git a/Runtime/Scripts/SceneImporter/ImporterSkinning.cs b/Runtime/Scripts/SceneImporter/ImporterSkinning.cs index 17eede369..872e2dd30 100644 --- a/Runtime/Scripts/SceneImporter/ImporterSkinning.cs +++ b/Runtime/Scripts/SceneImporter/ImporterSkinning.cs @@ -29,7 +29,7 @@ protected virtual async Task SetupBones(Skin skin, SkinnedMeshRenderer renderer, { AccessorId = skin.InverseBindMatrices, bufferData = bufferData.bufferData, - Offset = bufferData.ChunkOffset + Offset = bufferData.ChunkDataOffset }; GLTFHelpers.BuildBindPoseSamplers(ref attributeAccessor); diff --git a/Runtime/Scripts/SceneImporter/ImporterTextures.cs b/Runtime/Scripts/SceneImporter/ImporterTextures.cs index fac0ab8bc..22847448f 100644 --- a/Runtime/Scripts/SceneImporter/ImporterTextures.cs +++ b/Runtime/Scripts/SceneImporter/ImporterTextures.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -165,7 +165,7 @@ private Stream GetImageStream(GLTFImage image, int imageCacheIndex) BufferCacheData bufferContents = _assetCache.BufferCache[bufferView.Buffer.Id]; if (bufferContents.bufferData.IsCreated) { - bufferContents.Stream.Position = bufferView.ByteOffset + bufferContents.ChunkOffset; + bufferContents.Stream.Position = bufferView.ByteOffset + bufferContents.ChunkDataOffset; stream = new SubStream(bufferContents.Stream, 0, bufferView.ByteLength); } } @@ -874,7 +874,7 @@ protected virtual void ConstructImageFromGLB(GLTFImage image, int imageCacheInde var data = new byte[bufferView.ByteLength]; var bufferContents = _assetCache.BufferCache[bufferView.Buffer.Id]; - bufferContents.Stream.Position = bufferView.ByteOffset + bufferContents.ChunkOffset; + bufferContents.Stream.Position = bufferView.ByteOffset + bufferContents.ChunkDataOffset; bufferContents.Stream.Read(data, 0, data.Length); texture.LoadImage(data); From 9a279c82e135d230515cb7ebbeb26ef348f43a38 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Tue, 23 Jun 2026 02:55:57 -0700 Subject: [PATCH 3/5] Upgrade data type for sizes, lengths, offsets, etc to 64-bit `long` --- .../GLTFSerialization/AttributeAccessor.cs | 2 +- .../Plugins/GLTFSerialization/GLBBuilder.cs | 38 ++--- .../Plugins/GLTFSerialization/GLBObject.cs | 10 +- .../Plugins/GLTFSerialization/GLTFHelpers.cs | 6 +- .../Plugins/GLTFSerialization/GLTFParser.cs | 18 ++- .../GLTFSerialization/Schema/Accessor.cs | 150 +++++++++--------- .../Schema/AccessorSparse.cs | 2 +- .../Schema/AccessorSparseIndices.cs | 2 +- .../Schema/AccessorSparseValues.cs | 2 +- .../GLTFSerialization/Schema/BufferView.cs | 4 +- .../GLTFSerialization/Schema/GLTFBuffer.cs | 4 +- .../Utilities/JsonReaderExtensions.cs | 5 + .../Utilities/StreamExtensions.cs | 14 +- Runtime/Scripts/Cache/BufferCacheData.cs | 2 +- Runtime/Scripts/GLTFSceneExporter.cs | 6 +- Runtime/Scripts/GLTFSceneImporter.cs | 2 +- .../SceneExporter/ExporterAccessors.cs | 100 ++++++------ .../Scripts/SceneExporter/ExporterTextures.cs | 6 +- .../Scripts/SceneImporter/ImporterMeshes.cs | 20 +-- 19 files changed, 208 insertions(+), 185 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/AttributeAccessor.cs b/Runtime/Plugins/GLTFSerialization/AttributeAccessor.cs index 383d9a341..f7679107f 100644 --- a/Runtime/Plugins/GLTFSerialization/AttributeAccessor.cs +++ b/Runtime/Plugins/GLTFSerialization/AttributeAccessor.cs @@ -9,7 +9,7 @@ public class AttributeAccessor public NumericArray AccessorContent { get; set; } public NativeArray bufferData { get; set; } - public uint Offset { get; set; } + public long Offset { get; set; } public AttributeAccessor() { diff --git a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs index de5bcc13c..49f9ffa19 100644 --- a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs +++ b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs @@ -220,11 +220,11 @@ public static void UpdateStream(GLBObject glb) // realloc of out of space if (glb.JsonChunkInfo.Length < gltfJsonStream.Length) { - uint proposedJsonChunkLength = (uint)System.Math.Min((long)gltfJsonStream.Length * 2, uint.MaxValue); // allocate double what is required + long proposedJsonChunkLength = System.Math.Min((long)gltfJsonStream.Length * 2, (long)uint.MaxValue); // allocate double what is required proposedJsonChunkLength = CalculateAlignment(proposedJsonChunkLength, 4); // chunks must be 4 byte aligned - uint amountToAddToFile = proposedJsonChunkLength - glb.JsonChunkInfo.Length; + long amountToAddToFile = proposedJsonChunkLength - glb.JsonChunkInfo.Length; // we have not yet initialized a json chunk before if (glb.JsonChunkInfo.Length == 0) @@ -263,7 +263,7 @@ public static void UpdateStream(GLBObject glb) glb.SetBinaryChunkStartPosition(newBinaryChunkDataStartPosition); if (glb.BinaryChunkInfo.Length > 0) { - uint lengthToCopy = glb.BinaryChunkInfo.Length + GLBHeader.GLB2_CHUNK_HEADER_SIZE; + long lengthToCopy = glb.BinaryChunkInfo.Length + GLBHeader.GLB2_CHUNK_HEADER_SIZE; // todo: we need to be able to copy while doing it with smaller buffers. Also int is smaller than uint, so this is not standards compliant. glb.Stream.CopyToSelf((int)newBinaryChunkDataStartPosition, @@ -281,12 +281,12 @@ public static void UpdateStream(GLBObject glb) // clear the buffer glb.Stream.Position = glb.JsonChunkInfo.StartPosition + GLBHeader.GLB2_CHUNK_HEADER_SIZE; - uint amountToCopy = glb.JsonChunkInfo.Length; + long amountToCopy = glb.JsonChunkInfo.Length; while (amountToCopy != 0) { - int currAmountToCopy = (int)System.Math.Min(amountToCopy, int.MaxValue); + long currAmountToCopy = System.Math.Min(amountToCopy, (long)int.MaxValue); byte[] filler = - Encoding.ASCII.GetBytes(new string(' ', currAmountToCopy)); + Encoding.ASCII.GetBytes(new string(' ', (int)currAmountToCopy)); glb.Stream.Write(filler, 0, filler.Length); amountToCopy -= (uint)currAmountToCopy; } @@ -324,10 +324,10 @@ private static BufferViewId _AddBinaryData(GLBObject glb, Stream binaryData, boo binaryData.Position = streamStartPosition; // Append new binary chunk to end - uint blobLengthAsUInt = CalculateAlignment((uint)(binaryData.Length - streamStartPosition), 4); - uint newBinaryBufferSize = glb.BinaryChunkInfo.Length + blobLengthAsUInt; - uint newGLBSize = glb.Header.FileLength + blobLengthAsUInt; - uint blobWritePosition = glb.Header.FileLength; + long blobLength = CalculateAlignment(binaryData.Length - streamStartPosition, 4); + long newBinaryBufferSize = glb.BinaryChunkInfo.Length + blobLength; + long newGLBSize = glb.Header.FileLength + blobLength; + long blobWritePosition = glb.Header.FileLength; // there was an existing file that had no binary chunk info previously if (glb.BinaryChunkInfo.Length == 0) @@ -337,7 +337,7 @@ private static BufferViewId _AddBinaryData(GLBObject glb, Stream binaryData, boo glb.SetBinaryChunkStartPosition(glb.Header.FileLength); // if 0, then appends chunk info at the end } - glb.Stream.SetLength(glb.Header.FileLength + blobLengthAsUInt); + glb.Stream.SetLength(glb.Header.FileLength + blobLength); glb.Stream.Position = blobWritePosition; // assuming the end of the file is the end of the binary chunk binaryData.CopyTo(glb.Stream); // make sure this doesn't supersize it @@ -359,8 +359,8 @@ private static BufferViewId _AddBinaryData(GLBObject glb, Stream binaryData, boo Id = 0, Root = glb.Root }, - ByteLength = blobLengthAsUInt, // figure out whether glb size is wrong or if documentation is unclear - ByteOffset = glb.BinaryChunkInfo.Length - blobLengthAsUInt, + ByteLength = blobLength, // figure out whether glb size is wrong or if documentation is unclear + ByteOffset = glb.BinaryChunkInfo.Length - blobLength, Name = bufferViewName }; @@ -395,10 +395,10 @@ public static void MergeGLBs(GLBObject mergeTo, GLBObject mergeFrom) // 2) copy merge from binary data to merge to binary data // 3) Fix up buffer views to be the new offset int previousBufferViewsCount = mergeTo.Root.BufferViews?.Count ?? 0; - uint previousBufferSize = mergeTo.BinaryChunkInfo.Length; + long previousBufferSize = mergeTo.BinaryChunkInfo.Length; GLTFHelpers.MergeGLTF(mergeTo.Root, mergeFrom.Root); _AddBinaryData(mergeTo, mergeFrom.Stream, false, mergeFrom.BinaryChunkInfo.StartPosition + GLBHeader.GLB2_CHUNK_HEADER_SIZE); - uint bufferSizeDiff = + long bufferSizeDiff = mergeTo.BinaryChunkInfo.Length - previousBufferSize; // calculate buffer size change to update the byte offsets of the appended buffer views @@ -427,9 +427,9 @@ public static void RemoveBinaryData(GLBObject glb, BufferViewId bufferViewId) int id = bufferViewId.Id; if (bufferViewToRemove.ByteOffset + bufferViewToRemove.ByteLength == glb.BinaryChunkInfo.Length) { - uint bufferViewLengthAsUint = bufferViewToRemove.ByteLength; - glb.SetFileLength(glb.Header.FileLength - bufferViewLengthAsUint); - glb.SetBinaryChunkLength(glb.BinaryChunkInfo.Length - bufferViewLengthAsUint); + long bufferViewLength = bufferViewToRemove.ByteLength; + glb.SetFileLength(glb.Header.FileLength - bufferViewLength); + glb.SetBinaryChunkLength(glb.BinaryChunkInfo.Length - bufferViewLength); if (glb.BinaryChunkInfo.Length == 0) { glb.Root.Buffers.RemoveAt(0); @@ -527,7 +527,7 @@ private static void WriteChunkHeader(Stream stream, GLBChunkInfo chunkInfo) stream.Write(typeBytes, 0, lengthBytes.Length); } - public static uint CalculateAlignment(uint currentSize, uint byteAlignment) + public static long CalculateAlignment(long currentSize, long byteAlignment) { return (currentSize + byteAlignment - 1) / byteAlignment * byteAlignment; } diff --git a/Runtime/Plugins/GLTFSerialization/GLBObject.cs b/Runtime/Plugins/GLTFSerialization/GLBObject.cs index 2196ac101..db5b7f085 100644 --- a/Runtime/Plugins/GLTFSerialization/GLBObject.cs +++ b/Runtime/Plugins/GLTFSerialization/GLBObject.cs @@ -16,7 +16,7 @@ public enum GLBChunkFormat : uint public struct GLBHeader { public uint Version { get; set; } - public uint FileLength { get; set; } + public long FileLength { get; set; } public static readonly uint GLB2_FILE_HEADER_SIZE = 12; public static readonly uint GLB2_CHUNK_HEADER_SIZE = 8; @@ -33,7 +33,7 @@ public struct GLBHeader public struct GLBChunkInfo { public long StartPosition; - public uint Length; + public long Length; public GLBChunkFormat Type; } @@ -89,7 +89,7 @@ internal GLBObject() { } - internal void SetFileLength(uint newHeaderLength) + internal void SetFileLength(long newHeaderLength) { _glbHeader.FileLength = newHeaderLength; } @@ -99,7 +99,7 @@ internal void SetJsonChunkStartPosition(long startPosition) _jsonChunkInfo.StartPosition = startPosition; } - internal void SetJsonChunkLength(uint jsonChunkLength) + internal void SetJsonChunkLength(long jsonChunkLength) { _jsonChunkInfo.Length = jsonChunkLength; } @@ -109,7 +109,7 @@ internal void SetBinaryChunkStartPosition(long startPosition) _binaryChunkInfo.StartPosition = startPosition; } - internal void SetBinaryChunkLength(uint binaryChunkLength) + internal void SetBinaryChunkLength(long binaryChunkLength) { _binaryChunkInfo.Length = binaryChunkLength; if (Root.Buffers == null) diff --git a/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs b/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs index df6b25cf0..875e10c9d 100644 --- a/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs +++ b/Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using GLTF.Schema; @@ -522,7 +522,7 @@ private static void LoadBufferView(AttributeAccessor attributeAccessor, out Nati LoadBufferView(attributeAccessor.AccessorId.Value.BufferView?.Value, attributeAccessor.Offset, attributeAccessor.bufferData, out bufferViewCache); } - internal static void LoadBufferView(BufferView bufferView, uint Offset, NativeArray nativeBuffer, out NativeArray bufferViewCache) + internal static void LoadBufferView(BufferView bufferView, long Offset, NativeArray nativeBuffer, out NativeArray bufferViewCache) { // The bufferView can be null for sparse buffers with just a count. // In that case, this is a buffer padded with zeros, so we can just return the nativeBuffer. @@ -532,7 +532,7 @@ internal static void LoadBufferView(BufferView bufferView, uint Offset, NativeAr return; } - uint totalOffset = bufferView.ByteOffset + Offset; + long totalOffset = bufferView.ByteOffset + Offset; bufferViewCache = nativeBuffer.GetSubArray((int)totalOffset, (int)bufferView.ByteLength); } diff --git a/Runtime/Plugins/GLTFSerialization/GLTFParser.cs b/Runtime/Plugins/GLTFSerialization/GLTFParser.cs index 00f7009f4..3b2f64673 100644 --- a/Runtime/Plugins/GLTFSerialization/GLTFParser.cs +++ b/Runtime/Plugins/GLTFSerialization/GLTFParser.cs @@ -147,9 +147,25 @@ private static uint GetUInt32(Stream stream) { var uintSize = sizeof(uint); byte[] headerBuffer = new byte[uintSize]; - stream.Read(headerBuffer, 0, uintSize); + int bytesRead = stream.Read(headerBuffer, 0, uintSize); + if (bytesRead != uintSize) + { + throw new EndOfStreamException("Unexpected end of stream while reading uint32."); + } return BitConverter.ToUInt32(headerBuffer, 0); } + + private static ulong GetUInt64(Stream stream) + { + var ulongSize = sizeof(ulong); + byte[] headerBuffer = new byte[ulongSize]; + int bytesRead = stream.Read(headerBuffer, 0, ulongSize); + if (bytesRead != ulongSize) + { + throw new EndOfStreamException("Unexpected end of stream while reading uint64."); + } + return BitConverter.ToUInt64(headerBuffer, 0); + } } } diff --git a/Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs b/Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs index c3e737c0f..3e436373e 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs @@ -25,7 +25,7 @@ public class Accessor : GLTFChildOfRootProperty /// This must be a multiple of the size of the component datatype. /// 0 /// - public uint ByteOffset; + public long ByteOffset; /// /// The datatype of components in the attribute. @@ -50,7 +50,7 @@ public class Accessor : GLTFChildOfRootProperty /// with the number of bytes or number of components. /// 1 /// - public uint Count; + public long Count; /// /// Specifies if the attribute is a scalar, vector, or matrix, @@ -255,65 +255,65 @@ public override void Serialize(JsonWriter writer) writer.WriteEndObject(); } - private static unsafe sbyte GetByteElement(NativeArray buffer, uint byteOffset) + private static unsafe sbyte GetByteElement(NativeArray buffer, long byteOffset) { return *((sbyte*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(buffer) + (int)byteOffset); } - private static unsafe byte GetUByteElement(NativeArray buffer, uint byteOffset) + private static unsafe byte GetUByteElement(NativeArray buffer, long byteOffset) { return *((byte*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(buffer) + (int)byteOffset); } - private static unsafe short GetShortElement(NativeArray buffer, uint byteOffset) + private static unsafe short GetShortElement(NativeArray buffer, long byteOffset) { return *((short*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(buffer) + (int)byteOffset); } - private static unsafe ushort GetUShortElement(NativeArray buffer, uint byteOffset) + private static unsafe ushort GetUShortElement(NativeArray buffer, long byteOffset) { return *((ushort*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(buffer) + (int)byteOffset); } - private static unsafe uint GetUIntElement(NativeArray buffer, uint byteOffset) + private static unsafe uint GetUIntElement(NativeArray buffer, long byteOffset) { return *((uint*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(buffer) + (int)byteOffset); } - private static unsafe UInt16 GetUInt16Element(NativeArray buffer, uint byteOffset) + private static unsafe UInt16 GetUInt16Element(NativeArray buffer, long byteOffset) { return *((UInt16*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(buffer) + (int)byteOffset); } - private static unsafe float GetFloatElement(NativeArray buffer, uint byteOffset) + private static unsafe float GetFloatElement(NativeArray buffer, long byteOffset) { return *((float*)NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(buffer) + (int)byteOffset); } - private static unsafe sbyte GetByteElement(void* buffer, uint byteOffset) + private static unsafe sbyte GetByteElement(void* buffer, long byteOffset) { return *(sbyte*)(((byte*)buffer) + byteOffset); } - private static unsafe float2 GetByte2Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float2 GetByte2Element(void* buffer, long byteOffset, float maxValue) { var p = (sbyte*)(((byte*)buffer) + byteOffset); return new float2(*p / maxValue, *(p + 1) / maxValue); } - private static unsafe float3 GetByte3Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float3 GetByte3Element(void* buffer, long byteOffset, float maxValue) { var p = (sbyte*)(((byte*)buffer) + byteOffset); return new float3(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue); } - private static unsafe float4 GetByte4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4 GetByte4Element(void* buffer, long byteOffset, float maxValue) { var p = (sbyte*)(((byte*)buffer) + byteOffset); return new float4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue); } - private static unsafe float4x4 GetByte4x4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4x4 GetByte4x4Element(void* buffer, long byteOffset, float maxValue) { var p = (sbyte*)(((byte*)buffer) + byteOffset); return new float4x4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue, @@ -322,30 +322,30 @@ private static unsafe float4x4 GetByte4x4Element(void* buffer, uint byteOffset, *(p + 12) / maxValue, *(p + 13) / maxValue, *(p + 14) / maxValue, *(p + 15) / maxValue); } - private static unsafe byte GetUByteElement(void* buffer, uint byteOffset) + private static unsafe byte GetUByteElement(void* buffer, long byteOffset) { return *(byte*)(((byte*)buffer) + byteOffset); } - private static unsafe float2 GetUByte2Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float2 GetUByte2Element(void* buffer, long byteOffset, float maxValue) { var p = (byte*)(((byte*)buffer) + byteOffset); return new float2(*p / maxValue, *(p + 1) / maxValue); } - private static unsafe float3 GetUByte3Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float3 GetUByte3Element(void* buffer, long byteOffset, float maxValue) { var p = (byte*)(((byte*)buffer) + byteOffset); return new float3(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue); } - private static unsafe float4 GetUByte4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4 GetUByte4Element(void* buffer, long byteOffset, float maxValue) { var p = (byte*)(((byte*)buffer) + byteOffset); return new float4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue); } - private static unsafe float4x4 GetUByte4x4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4x4 GetUByte4x4Element(void* buffer, long byteOffset, float maxValue) { var p = (byte*)(((byte*)buffer) + byteOffset); return new float4x4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue, @@ -354,30 +354,30 @@ private static unsafe float4x4 GetUByte4x4Element(void* buffer, uint byteOffset, *(p + 12) / maxValue, *(p + 13) / maxValue, *(p + 14) / maxValue, *(p + 15) / maxValue); } - private static unsafe short GetShortElement(void* buffer, uint byteOffset) + private static unsafe short GetShortElement(void* buffer, long byteOffset) { return *(short*)(((byte*)buffer) + byteOffset); } - private static unsafe float2 GetShort2Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float2 GetShort2Element(void* buffer, long byteOffset, float maxValue) { var p = (short*)(((byte*)buffer) + byteOffset); return new float2(*p / maxValue, *(p + 1) / maxValue); } - private static unsafe float3 GetShort3Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float3 GetShort3Element(void* buffer, long byteOffset, float maxValue) { var p = (short*)(((byte*)buffer) + byteOffset); return new float3(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue); } - private static unsafe float4 GetShort4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4 GetShort4Element(void* buffer, long byteOffset, float maxValue) { var p = (short*)(((byte*)buffer) + byteOffset); return new float4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue); } - private static unsafe float4x4 GetShort4x4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4x4 GetShort4x4Element(void* buffer, long byteOffset, float maxValue) { var p = (short*)(((byte*)buffer) + byteOffset); return new float4x4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue, @@ -386,24 +386,24 @@ private static unsafe float4x4 GetShort4x4Element(void* buffer, uint byteOffset, *(p + 12) / maxValue, *(p + 13) / maxValue, *(p + 14) / maxValue, *(p + 15) / maxValue); } - private static unsafe ushort GetUShortElement(void* buffer, uint byteOffset) + private static unsafe ushort GetUShortElement(void* buffer, long byteOffset) { return *(ushort*)(((byte*)buffer) + byteOffset); } - private static unsafe float2 GetUShort2Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float2 GetUShort2Element(void* buffer, long byteOffset, float maxValue) { var p = (ushort*)(((byte*)buffer) + byteOffset); return new float2(*p / maxValue, *(p + 1) / maxValue); } - private static unsafe float3 GetUShort3Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float3 GetUShort3Element(void* buffer, long byteOffset, float maxValue) { var p = (ushort*)(((byte*)buffer) + byteOffset); return new float3(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue); } - private static unsafe float4x4 GetUShort4x4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4x4 GetUShort4x4Element(void* buffer, long byteOffset, float maxValue) { var p = (ushort*)(((byte*)buffer) + byteOffset); return new float4x4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue, @@ -412,106 +412,106 @@ private static unsafe float4x4 GetUShort4x4Element(void* buffer, uint byteOffset *(p + 12) / maxValue, *(p + 13) / maxValue, *(p + 14) / maxValue, *(p + 15) / maxValue); } - private static unsafe float4 GetUShort4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4 GetUShort4Element(void* buffer, long byteOffset, float maxValue) { var p = (ushort*)(((byte*)buffer) + byteOffset); return new float4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue); } - private static unsafe uint GetUIntElement(void* buffer, uint byteOffset) + private static unsafe uint GetUIntElement(void* buffer, long byteOffset) { return *(uint*)(((byte*)buffer) + byteOffset); } - private static unsafe float2 GetUInt2Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float2 GetUInt2Element(void* buffer, long byteOffset, float maxValue) { var p = (uint*)(((byte*)buffer) + byteOffset); return new float2(*p / maxValue, *(p + 1) / maxValue); } - private static unsafe float3 GetUInt3Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float3 GetUInt3Element(void* buffer, long byteOffset, float maxValue) { var p = (uint*)(((byte*)buffer) + byteOffset); return new float3(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue); } - private static unsafe float4 GetUInt4Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4 GetUInt4Element(void* buffer, long byteOffset, float maxValue) { var p = (uint*)(((byte*)buffer) + byteOffset); return new float4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue); } - private static unsafe UInt16 GetUInt16Element(void* buffer, uint byteOffset) + private static unsafe UInt16 GetUInt16Element(void* buffer, long byteOffset) { return *(UInt16*)(((byte*)buffer) + byteOffset); } - private static unsafe float2 GetUInt16_2_Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float2 GetUInt16_2_Element(void* buffer, long byteOffset, float maxValue) { var p = (UInt16*)(((byte*)buffer) + byteOffset); return new float2(*p / maxValue, *(p + 1) / maxValue); } - private static unsafe float3 GetUInt16_3_Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float3 GetUInt16_3_Element(void* buffer, long byteOffset, float maxValue) { var p = (UInt16*)(((byte*)buffer) + byteOffset); return new float3(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue); } - private static unsafe float4 GetUInt16_4_Element(void* buffer, uint byteOffset, float maxValue) + private static unsafe float4 GetUInt16_4_Element(void* buffer, long byteOffset, float maxValue) { var p = (UInt16*)(((byte*)buffer) + byteOffset); return new float4(*p / maxValue, *(p + 1) / maxValue, *(p + 2) / maxValue, *(p + 3) / maxValue); } - private static unsafe float GetFloatElement(void* buffer, uint byteOffset) + private static unsafe float GetFloatElement(void* buffer, long byteOffset) { return *(float*)(((byte*)buffer) + byteOffset); } - private static unsafe float2 GetFloat2Element(void* buffer, uint byteOffset) + private static unsafe float2 GetFloat2Element(void* buffer, long byteOffset) { var p = (float*)(((byte*)buffer) + byteOffset); return new float2(*p, *(p + 1)); } - private static unsafe float3 GetFloat3Element(void* buffer, uint byteOffset) + private static unsafe float3 GetFloat3Element(void* buffer, long byteOffset) { var p = (float*)(((byte*)buffer) + byteOffset); return new float3(*p, *(p + 1), *(p + 2)); } - private static unsafe float4 GetFloat4Element(void* buffer, uint byteOffset) + private static unsafe float4 GetFloat4Element(void* buffer, long byteOffset) { var p = (float*)(((byte*)buffer) + byteOffset); return new float4(*p, *(p + 1),*(p + 2),*(p + 3)); } - private static unsafe float4x4 GetFloat4x4Element(void* buffer, uint byteOffset) + private static unsafe float4x4 GetFloat4x4Element(void* buffer, long byteOffset) { var p = (float4*)(((byte*)buffer) + byteOffset); return new float4x4(*p, *(p + 1),*(p + 2),*(p + 3)); } - private static unsafe float4 GetColorElement(void* buffer, uint byteOffset) + private static unsafe float4 GetColorElement(void* buffer, long byteOffset) { var p = (float*)(((byte*)buffer) + byteOffset); return new float4(*p, *(p + 1),*(p + 2),*(p + 3)); } - private static unsafe float4 GetColorElement(void* buffer, uint byteOffset, float alpha) + private static unsafe float4 GetColorElement(void* buffer, long byteOffset, float alpha) { var p = (float*)(((byte*)buffer) + byteOffset); return new float4(*p, *(p + 1),*(p + 2), alpha); } - public static unsafe float3[] AsSparseFloat3Array(Accessor paraAccessor, ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalizeIntValues = true) + public static unsafe float3[] AsSparseFloat3Array(Accessor paraAccessor, ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalizeIntValues = true) { var Count = paraAccessor.Sparse.Count; var ComponentType = paraAccessor.ComponentType; var arr = new float3[paraAccessor.Sparse.Count]; - var totalByteOffset = (uint)paraAccessor.Sparse.Values.ByteOffset + offset; + long totalByteOffset = paraAccessor.Sparse.Values.ByteOffset + offset; GetTypeDetails(paraAccessor.ComponentType, out uint componentSize, out float maxValue); uint stride = componentSize * 3; @@ -532,7 +532,7 @@ public static unsafe float3[] AsSparseFloat3Array(Accessor paraAccessor, ref Num return arr; } - public static unsafe float3[] AsSparseFloat3ArrayConversion(Accessor paraAccessor, ref NumericArray contents, NativeArray bufferViewData, float3 conversion, uint offset = 0, bool normalizeIntValues = true) + public static unsafe float3[] AsSparseFloat3ArrayConversion(Accessor paraAccessor, ref NumericArray contents, NativeArray bufferViewData, float3 conversion, long offset = 0, bool normalizeIntValues = true) { var Count = paraAccessor.Sparse.Count; var ComponentType = paraAccessor.ComponentType; @@ -559,7 +559,7 @@ public static unsafe float3[] AsSparseFloat3ArrayConversion(Accessor paraAccesso return arr; } - public static unsafe uint[] AsSparseUIntArray(Accessor paraAccessor, ref NumericArray contents, NativeArray bufferViewData, uint offset = 0) + public static unsafe uint[] AsSparseUIntArray(Accessor paraAccessor, ref NumericArray contents, NativeArray bufferViewData, long offset = 0) { var arr = new uint[paraAccessor.Sparse.Count]; var totalByteOffset = paraAccessor.Sparse.Indices.ByteOffset + offset; @@ -622,7 +622,7 @@ internal static void GetTypeDetails( } } - public unsafe byte[] AsUByteArray(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0) + public unsafe byte[] AsUByteArray(ref NumericArray contents, NativeArray bufferViewData, long offset = 0) { if (contents.AsBytes != null) { @@ -652,7 +652,7 @@ public unsafe byte[] AsUByteArray(ref NumericArray contents, NativeArray b return arr; } - public unsafe uint[] AsUIntArray(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0) + public unsafe uint[] AsUIntArray(ref NumericArray contents, NativeArray bufferViewData, long offset = 0) { if (contents.AsUInts != null) { @@ -692,7 +692,7 @@ public unsafe uint[] AsUIntArray(ref NumericArray contents, NativeArray bu return arr; } - public unsafe float[] AsFloatArray(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalizeIntValues = true) + public unsafe float[] AsFloatArray(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalizeIntValues = true) { if (contents.AsUInts != null) { @@ -712,7 +712,7 @@ public unsafe float[] AsFloatArray(ref NumericArray contents, NativeArray return arr; } - uint totalByteOffset = ByteOffset + offset; + long totalByteOffset = ByteOffset + offset; GetTypeDetails(ComponentType, out uint componentSize, out float maxValue); if (normalizeIntValues) maxValue = 1f; @@ -734,7 +734,7 @@ public unsafe float[] AsFloatArray(ref NumericArray contents, NativeArray return arr; } - public unsafe float2[] AsFloat2Array(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalizeIntValues = true) + public unsafe float2[] AsFloat2Array(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalizeIntValues = true) { if (contents.AsFloat2s != null) { @@ -781,7 +781,7 @@ public unsafe float2[] AsFloat2Array(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalizeIntValues = true) + public unsafe float2[] AsTexcoordArray(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalizeIntValues = true) { if (contents.AsFloat2s != null) { @@ -828,7 +828,7 @@ public unsafe float2[] AsTexcoordArray(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalizeIntValues = true) + public unsafe float3[] AsFloat3Array(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalizeIntValues = true) { if (contents.AsFloat3s != null) { @@ -871,7 +871,7 @@ public unsafe float3[] AsFloat3Array(ref NumericArray contents, NativeArray bufferViewData, float3 conversion, uint offset = 0, bool normalizeIntValues = true) + public unsafe float3[] AsFloat3ArrayConversion(ref NumericArray contents, NativeArray bufferViewData, float3 conversion, long offset = 0, bool normalizeIntValues = true) { if (contents.AsFloat3s != null) { @@ -907,7 +907,7 @@ public unsafe float3[] AsFloat3ArrayConversion(ref NumericArray contents, Native return arr; } - public unsafe float4[] AsFloat4Array(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalizeIntValues = true) + public unsafe float4[] AsFloat4Array(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalizeIntValues = true) { if (contents.AsFloat4s != null) { @@ -955,7 +955,7 @@ public unsafe float4[] AsFloat4Array(ref NumericArray contents, NativeArray bufferViewData, float4 conversion, uint offset = 0, bool normalizeIntValues = true) + public unsafe float4[] AsFloat4ArrayConversion(ref NumericArray contents, NativeArray bufferViewData, float4 conversion, long offset = 0, bool normalizeIntValues = true) { if (contents.AsFloat4s != null) { @@ -996,7 +996,7 @@ public unsafe float4[] AsFloat4ArrayConversion(ref NumericArray contents, Native return arr; } - public unsafe float4[] AsColorArray(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalizeIntValues = true) + public unsafe float4[] AsColorArray(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalizeIntValues = true) { if (contents.AsFloat4s != null) { @@ -1055,7 +1055,7 @@ public unsafe float4[] AsColorArray(ref NumericArray contents, NativeArray return arr; } - public float3[] AsVertexArray(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalized = true) + public float3[] AsVertexArray(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalized = true) { if (contents.AsFloat3s != null) { @@ -1069,7 +1069,7 @@ public float3[] AsVertexArray(ref NumericArray contents, NativeArray buffe return contents.AsFloat3s; } - public float3[] AsNormalArray(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalized = true) + public float3[] AsNormalArray(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalized = true) { if (contents.AsFloat3s != null) { @@ -1085,7 +1085,7 @@ public float3[] AsNormalArray(ref NumericArray contents, NativeArray buffe return contents.AsFloat3s; } - public float4[] AsTangentArray(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalized = true) + public float4[] AsTangentArray(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalized = true) { if (contents.AsFloat4s != null) { @@ -1101,7 +1101,7 @@ public float4[] AsTangentArray(ref NumericArray contents, NativeArray buff return contents.AsFloat4s; } - public uint[] AsTriangles(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0) + public uint[] AsTriangles(ref NumericArray contents, NativeArray bufferViewData, long offset = 0) { if (contents.AsTriangles != null) { @@ -1113,7 +1113,7 @@ public uint[] AsTriangles(ref NumericArray contents, NativeArray bufferVie return contents.AsTriangles; } - public unsafe float4x4[] AsMatrix4x4Array(ref NumericArray contents, NativeArray bufferViewData, uint offset = 0, bool normalizeIntValues = true) + public unsafe float4x4[] AsMatrix4x4Array(ref NumericArray contents, NativeArray bufferViewData, long offset = 0, bool normalizeIntValues = true) { if (contents.AsMatrix4x4s != null) { @@ -1133,7 +1133,7 @@ public unsafe float4x4[] AsMatrix4x4Array(ref NumericArray contents, NativeArray return arr; } - uint totalByteOffset = ByteOffset + offset; + long totalByteOffset = ByteOffset + offset; GetTypeDetails(ComponentType, out uint componentSize, out float maxValue); var bufferPointer = NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(bufferViewData); @@ -1159,7 +1159,7 @@ public unsafe float4x4[] AsMatrix4x4Array(ref NumericArray contents, NativeArray return arr; } - private static int GetDiscreteElement(NativeArray bufferViewData, uint offset, GLTFComponentType type) + private static int GetDiscreteElement(NativeArray bufferViewData, long offset, GLTFComponentType type) { switch (type) { @@ -1186,7 +1186,7 @@ private static int GetDiscreteElement(NativeArray bufferViewData, uint off } } - private static unsafe int GetDiscreteElement(void* bufferViewData, uint offset, GLTFComponentType type) + private static unsafe int GetDiscreteElement(void* bufferViewData, long offset, GLTFComponentType type) { switch (type) { @@ -1213,7 +1213,7 @@ private static unsafe int GetDiscreteElement(void* bufferViewData, uint offset, } } - private static unsafe float4 GetDiscreteColorElement(void* bufferViewData, uint offset, GLTFComponentType type, float maxValue) + private static unsafe float4 GetDiscreteColorElement(void* bufferViewData, long offset, GLTFComponentType type, float maxValue) { switch (type) { @@ -1240,7 +1240,7 @@ private static unsafe float4 GetDiscreteColorElement(void* bufferViewData, uint } } - private static unsafe float4 GetDiscreteColorElement(void* bufferViewData, uint offset, GLTFComponentType type, float maxValue, float alpha) + private static unsafe float4 GetDiscreteColorElement(void* bufferViewData, long offset, GLTFComponentType type, float maxValue, float alpha) { switch (type) { @@ -1267,7 +1267,7 @@ private static unsafe float4 GetDiscreteColorElement(void* bufferViewData, uint } } - private static unsafe float4x4 GetDiscreteFloat4x4Element(void* bufferViewData, uint offset, GLTFComponentType type, float maxValue) + private static unsafe float4x4 GetDiscreteFloat4x4Element(void* bufferViewData, long offset, GLTFComponentType type, float maxValue) { switch (type) { @@ -1294,7 +1294,7 @@ private static unsafe float4x4 GetDiscreteFloat4x4Element(void* bufferViewData, } } - private static unsafe float4 GetDiscreteFloat4Element(void* bufferViewData, uint offset, GLTFComponentType type, float maxValue) + private static unsafe float4 GetDiscreteFloat4Element(void* bufferViewData, long offset, GLTFComponentType type, float maxValue) { switch (type) { @@ -1321,7 +1321,7 @@ private static unsafe float4 GetDiscreteFloat4Element(void* bufferViewData, uint } } - private static unsafe float3 GetDiscreteFloat3Element(void* bufferViewData, uint offset, GLTFComponentType type, float maxValue) + private static unsafe float3 GetDiscreteFloat3Element(void* bufferViewData, long offset, GLTFComponentType type, float maxValue) { switch (type) { @@ -1348,7 +1348,7 @@ private static unsafe float3 GetDiscreteFloat3Element(void* bufferViewData, uint } } - private static unsafe float2 GetDiscreteFloat2Element(void* bufferViewData, uint offset, GLTFComponentType type, float maxValue) + private static unsafe float2 GetDiscreteFloat2Element(void* bufferViewData, long offset, GLTFComponentType type, float maxValue) { switch (type) { @@ -1376,7 +1376,7 @@ private static unsafe float2 GetDiscreteFloat2Element(void* bufferViewData, uint } // technically byte and short are not spec compliant for unsigned types, but various files have it - private static uint GetUnsignedDiscreteElement(NativeArray bufferViewData, uint offset, GLTFComponentType type) + private static uint GetUnsignedDiscreteElement(NativeArray bufferViewData, long offset, GLTFComponentType type) { switch (type) { @@ -1408,7 +1408,7 @@ private static uint GetUnsignedDiscreteElement(NativeArray bufferViewData, } } - private static unsafe uint GetUnsignedDiscreteElement(void* bufferViewData, uint offset, GLTFComponentType type) + private static unsafe uint GetUnsignedDiscreteElement(void* bufferViewData, long offset, GLTFComponentType type) { switch (type) { diff --git a/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparse.cs b/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparse.cs index 4235bb416..868e5c6a8 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparse.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparse.cs @@ -9,7 +9,7 @@ public class AccessorSparse : GLTFProperty /// Number of entries stored in the sparse array. /// 1 /// - public int Count; + public long Count; /// /// Index array of size `count` that points to those accessor attributes that diff --git a/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparseIndices.cs b/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparseIndices.cs index 8f4693938..a8a12b044 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparseIndices.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparseIndices.cs @@ -15,7 +15,7 @@ public class AccessorSparseIndices : GLTFProperty /// The offset relative to the start of the bufferView in bytes. Must be aligned. /// 0 /// - public int ByteOffset; + public long ByteOffset; /// /// The indices data type. Valid values correspond to WebGL enums: diff --git a/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparseValues.cs b/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparseValues.cs index f017f17d4..ad2cc93c9 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparseValues.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/AccessorSparseValues.cs @@ -15,7 +15,7 @@ public class AccessorSparseValues : GLTFProperty /// The offset relative to the start of the bufferView in bytes. Must be aligned. /// 0 /// - public int ByteOffset = 0; + public long ByteOffset = 0; public AccessorSparseValues() { diff --git a/Runtime/Plugins/GLTFSerialization/Schema/BufferView.cs b/Runtime/Plugins/GLTFSerialization/Schema/BufferView.cs index 10a0bc07e..76cb310b9 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/BufferView.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/BufferView.cs @@ -33,13 +33,13 @@ public class BufferView : GLTFChildOfRootProperty /// The offset into the buffer in bytes. /// 0 /// - public uint ByteOffset; + public long ByteOffset; /// /// The length of the bufferView in bytes. /// 0 /// - public uint ByteLength; + public long ByteLength; /// /// The stride, in bytes, between vertex attributes or other interleavable data. diff --git a/Runtime/Plugins/GLTFSerialization/Schema/GLTFBuffer.cs b/Runtime/Plugins/GLTFSerialization/Schema/GLTFBuffer.cs index 01af2a037..2754b6d58 100644 --- a/Runtime/Plugins/GLTFSerialization/Schema/GLTFBuffer.cs +++ b/Runtime/Plugins/GLTFSerialization/Schema/GLTFBuffer.cs @@ -19,7 +19,7 @@ public class GLTFBuffer : GLTFChildOfRootProperty /// The length of the buffer in bytes. /// 0 /// - public uint ByteLength; + public long ByteLength; public GLTFBuffer() { @@ -46,7 +46,7 @@ public static GLTFBuffer Deserialize(GLTFRoot root, JsonReader reader) buffer.Uri = reader.ReadAsString(); break; case "byteLength": - buffer.ByteLength = reader.ReadDoubleAsUInt32(); + buffer.ByteLength = (long)reader.ReadDoubleAsUInt64(); break; default: buffer.DefaultPropertyDeserializer(root, reader); diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/JsonReaderExtensions.cs b/Runtime/Plugins/GLTFSerialization/Utilities/JsonReaderExtensions.cs index c08acefc9..c19e54a73 100644 --- a/Runtime/Plugins/GLTFSerialization/Utilities/JsonReaderExtensions.cs +++ b/Runtime/Plugins/GLTFSerialization/Utilities/JsonReaderExtensions.cs @@ -8,5 +8,10 @@ public static uint ReadDoubleAsUInt32(this JsonReader reader) { return (uint)System.Math.Round(reader.ReadAsDouble().Value); } + + public static ulong ReadDoubleAsUInt64(this JsonReader reader) + { + return (ulong)System.Math.Round(reader.ReadAsDouble().Value); + } } } diff --git a/Runtime/Plugins/GLTFSerialization/Utilities/StreamExtensions.cs b/Runtime/Plugins/GLTFSerialization/Utilities/StreamExtensions.cs index f214ac3c7..0029d4c5f 100644 --- a/Runtime/Plugins/GLTFSerialization/Utilities/StreamExtensions.cs +++ b/Runtime/Plugins/GLTFSerialization/Utilities/StreamExtensions.cs @@ -38,27 +38,29 @@ public static void CopyTo(this Stream source, Stream destination) /// Offset into stream to copy /// Amount of stream to copy /// Size of array to use for each copy - public static void CopyToSelf(this Stream source, int destinationOffset, uint amountToCopy) + public static void CopyToSelf(this Stream source, long destinationOffset, long amountToCopy) { if (destinationOffset <= source.Position) throw new NotImplementedException("destination offset must be larger than source offset"); - int highwaterMark = 0; + long highwaterMark = 0; long initialOffset = source.Position; try { - int read; + long read; + // This value is limited to `_CopyBuffer.Length` aka `_DefaultCopyBufferSize`, + // which is limited to C#'s 32-bit managed arrays, so it should be a 32-bit integer. int amountToRead; while ((source.Position = initialOffset + amountToCopy - (amountToRead = (int)Math.Min(_CopyBuffer.Length, amountToCopy))) >= 0 && (read = source.Read(_CopyBuffer, 0, amountToRead)) != 0) { if (read > highwaterMark) highwaterMark = read; source.Position = destinationOffset + amountToCopy - read; - source.Write(_CopyBuffer, 0, read); - amountToCopy -= (uint)read; + source.Write(_CopyBuffer, 0, (int)read); + amountToCopy -= read; } } finally { - Array.Clear(_CopyBuffer, 0, highwaterMark); // clear only the most we used + Array.Clear(_CopyBuffer, 0, (int)highwaterMark); // clear only the most we used } } } diff --git a/Runtime/Scripts/Cache/BufferCacheData.cs b/Runtime/Scripts/Cache/BufferCacheData.cs index 2147ee02d..21bb7a230 100644 --- a/Runtime/Scripts/Cache/BufferCacheData.cs +++ b/Runtime/Scripts/Cache/BufferCacheData.cs @@ -8,7 +8,7 @@ public class BufferCacheData : IDisposable /// /// The offset in the stream where the chunk data starts, past the chunk header. /// - public uint ChunkDataOffset { get; set; } + public long ChunkDataOffset { get; set; } public System.IO.Stream Stream { get; set; } public NativeArray bufferData { get; set; } diff --git a/Runtime/Scripts/GLTFSceneExporter.cs b/Runtime/Scripts/GLTFSceneExporter.cs index e115f972a..7312c80a8 100644 --- a/Runtime/Scripts/GLTFSceneExporter.cs +++ b/Runtime/Scripts/GLTFSceneExporter.cs @@ -806,7 +806,7 @@ public void SaveGLBToStream(Stream stream, string sceneName) animationPointerResolver?.Resolve(this); - _buffer.ByteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Length, 4); + _buffer.ByteLength = CalculateAlignment(_bufferWriter.BaseStream.Length, 4); gltfSerializationMarker.Begin(); _root.Serialize(jsonWriter, true); @@ -817,7 +817,7 @@ public void SaveGLBToStream(Stream stream, string sceneName) jsonWriter.Flush(); // align to 4-byte boundary to comply with spec. - AlignToBoundary(jsonStream); + AlignToBoundary(jsonStream, (byte)'_'); AlignToBoundary(binStream, 0x00); int glbLength = (int)(GLTFHeaderSize + SectionHeaderSize + @@ -912,7 +912,7 @@ public void SaveGLTFandBin(string path, string fileName, bool exportTextures = t { AlignToBoundary(_bufferWriter.BaseStream, 0x00); _buffer.Uri = fileName + ".bin"; - _buffer.ByteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Length, 4); + _buffer.ByteLength = CalculateAlignment(_bufferWriter.BaseStream.Length, 4); } else { diff --git a/Runtime/Scripts/GLTFSceneImporter.cs b/Runtime/Scripts/GLTFSceneImporter.cs index 70fc5ddc9..4dbdf9895 100644 --- a/Runtime/Scripts/GLTFSceneImporter.cs +++ b/Runtime/Scripts/GLTFSceneImporter.cs @@ -1531,7 +1531,7 @@ protected virtual BufferCacheData ConstructBufferFromGLB(int bufferIndex) return new BufferCacheData { Stream = _gltfStream.Stream, - ChunkDataOffset = (uint)_gltfStream.Stream.Position, + ChunkDataOffset = _gltfStream.Stream.Position, bufferData = GetOrCreateNativeBuffer(_gltfStream.Stream), }; } diff --git a/Runtime/Scripts/SceneExporter/ExporterAccessors.cs b/Runtime/Scripts/SceneExporter/ExporterAccessors.cs index d70db01aa..08e110b3d 100644 --- a/Runtime/Scripts/SceneExporter/ExporterAccessors.cs +++ b/Runtime/Scripts/SceneExporter/ExporterAccessors.cs @@ -43,10 +43,10 @@ private static void CopyStream(Stream input, BinaryWriter output) /// space (' '). /// The boundary to align with, in bytes. /// - private static void AlignToBoundary(Stream stream, byte pad = (byte)' ', uint boundary = 4) + private static void AlignToBoundary(Stream stream, byte pad, long boundary = 4) { - uint currentLength = (uint)stream.Length; - uint newLength = CalculateAlignment(currentLength, boundary); + long currentLength = stream.Length; + long newLength = CalculateAlignment(currentLength, boundary); for (int i = 0; i < newLength - currentLength; i++) { stream.WriteByte(pad); @@ -60,7 +60,7 @@ private static void AlignToBoundary(Stream stream, byte pad = (byte)' ', uint bo /// The current size of the buffer. /// The number of bytes to align with. /// - public static uint CalculateAlignment(uint currentSize, uint byteAlignment) + public static long CalculateAlignment(long currentSize, long byteAlignment) { return (currentSize + byteAlignment - 1) / byteAlignment * byteAlignment; } @@ -70,7 +70,7 @@ private AccessorId ExportAccessorUint(Vector4[] arr) exportAccessorMarker.Begin(); exportAccessorUintArrayMarker.Begin(); - var count = (uint)arr.Length; + long count = (long)arr.Length; if (count == 0) { @@ -133,7 +133,7 @@ private AccessorId ExportAccessorUint(Vector4[] arr) accessor.Max = new List { maxX, maxY, maxZ, maxW }; AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); exportAccessorBufferWriteMarker.Begin(); foreach (var vec in arr) @@ -145,9 +145,9 @@ private AccessorId ExportAccessorUint(Vector4[] arr) } exportAccessorBufferWriteMarker.End(); - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); - accessor.BufferView = ExportBufferView((uint)byteOffset, (uint)byteLength); + accessor.BufferView = ExportBufferView(byteOffset, byteLength); var id = new AccessorId { @@ -168,7 +168,7 @@ private AccessorId ExportAccessorSwitchHandedness(Quaternion[] arr, bool invertL exportAccessorMarker.Begin(); exportAccessorVector4ArrayMarker.Begin(); - var count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -246,7 +246,7 @@ private AccessorId ExportAccessorSwitchHandedness(Quaternion[] arr, bool invertL accessor.Max = new List { maxX, maxY, maxZ, maxW }; AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); exportAccessorBufferWriteMarker.Begin(); #if USE_FAST_BINARY_WRITER @@ -262,9 +262,9 @@ private AccessorId ExportAccessorSwitchHandedness(Quaternion[] arr, bool invertL #endif exportAccessorBufferWriteMarker.End(); - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); - accessor.BufferView = ExportBufferView((uint)byteOffset, (uint)byteLength); + accessor.BufferView = ExportBufferView(byteOffset, byteLength); var id = new AccessorId { @@ -284,7 +284,7 @@ private AccessorId ExportAccessor(Matrix4x4[] arr) exportAccessorMarker.Begin(); exportAccessorMatrix4x4ArrayMarker.Begin(); - var count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -299,7 +299,7 @@ private AccessorId ExportAccessor(Matrix4x4[] arr) // Dont serialize min/max for matrices AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); exportAccessorBufferWriteMarker.Begin(); foreach (var mat in arr) @@ -316,9 +316,9 @@ private AccessorId ExportAccessor(Matrix4x4[] arr) } exportAccessorBufferWriteMarker.End(); - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); - accessor.BufferView = ExportBufferView((uint)byteOffset, (uint)byteLength); + accessor.BufferView = ExportBufferView(byteOffset, byteLength); var id = new AccessorId { @@ -339,7 +339,7 @@ private AccessorId ExportAccessor(Matrix4x4[] arr) /// /// The accessor id.You can get the actual accessor via val.Root.Accessors[val.Id]. /// - public AccessorId ExportAccessor(byte[] data, uint count, GLTFAccessorAttributeType type, GLTFComponentType componentType, List min, List max) + public AccessorId ExportAccessor(byte[] data, long count, GLTFAccessorAttributeType type, GLTFComponentType componentType, List min, List max) { exportAccessorMarker.Begin(); exportAccessorByteArrayMarker.Begin(); @@ -355,7 +355,7 @@ public AccessorId ExportAccessor(byte[] data, uint count, GLTFAccessorAttributeT accessor.ComponentType = componentType; AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); foreach (var v in data) { @@ -365,7 +365,7 @@ public AccessorId ExportAccessor(byte[] data, uint count, GLTFAccessorAttributeT accessor.Min = min; accessor.Max = max; - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); accessor.BufferView = ExportBufferView(byteOffset, byteLength); var id = new AccessorId @@ -386,7 +386,7 @@ public AccessorId ExportAccessor(byte[] arr) exportAccessorMarker.Begin(); exportAccessorByteArrayMarker.Begin(); - uint count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -415,7 +415,7 @@ public AccessorId ExportAccessor(byte[] arr) } AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 1); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 1); accessor.ComponentType = GLTFComponentType.UnsignedByte; @@ -427,7 +427,7 @@ public AccessorId ExportAccessor(byte[] arr) accessor.Min = new List { min }; accessor.Max = new List { max }; - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 1); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 1); accessor.BufferView = ExportBufferView(byteOffset, byteLength); @@ -449,7 +449,7 @@ private AccessorId ExportAccessor(float[] arr) exportAccessorMarker.Begin(); exportAccessorFloatArrayMarker.Begin(); - uint count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -480,7 +480,7 @@ private AccessorId ExportAccessor(float[] arr) exportAccessorMinMaxMarker.End(); AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, sizeof(float)); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, sizeof(float)); exportAccessorBufferWriteMarker.Begin(); accessor.ComponentType = GLTFComponentType.Float; @@ -498,7 +498,7 @@ private AccessorId ExportAccessor(float[] arr) accessor.Min = new List { min }; accessor.Max = new List { max }; - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); accessor.BufferView = ExportBufferView(byteOffset, byteLength); @@ -520,7 +520,7 @@ private AccessorId ExportAccessor(int[] arr, bool isIndices = false) exportAccessorMarker.Begin(); if (isIndices) exportAccessorIntArrayIndicesMarker.Begin(); else exportAccessorIntArrayMarker.Begin(); - uint count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -549,7 +549,7 @@ private AccessorId ExportAccessor(int[] arr, bool isIndices = false) } AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); // From the spec: // Values of the index accessor must not include the maximum value for the given component type, @@ -615,7 +615,7 @@ private AccessorId ExportAccessor(int[] arr, bool isIndices = false) accessor.Min = new List { min }; accessor.Max = new List { max }; - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); accessor.BufferView = ExportBufferView(byteOffset, byteLength); @@ -637,7 +637,7 @@ private AccessorId ExportAccessor(Vector2[] arr) exportAccessorMarker.Begin(); exportAccessorVector2ArrayMarker.Begin(); - uint count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -680,7 +680,7 @@ private AccessorId ExportAccessor(Vector2[] arr) accessor.Max = new List { maxX, maxY }; AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); foreach (var vec in arr) { @@ -688,7 +688,7 @@ private AccessorId ExportAccessor(Vector2[] arr) _bufferWriter.Write(vec.y); } - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); accessor.BufferView = ExportBufferView(byteOffset, byteLength); @@ -710,7 +710,7 @@ private AccessorId ExportAccessor(Vector3[] arr) exportAccessorMarker.Begin(); exportAccessorVector3ArrayMarker.Begin(); - uint count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -763,7 +763,7 @@ private AccessorId ExportAccessor(Vector3[] arr) accessor.Max = new List { maxX, maxY, maxZ }; AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); exportAccessorBufferWriteMarker.Begin(); #if USE_FAST_BINARY_WRITER @@ -778,7 +778,7 @@ private AccessorId ExportAccessor(Vector3[] arr) #endif exportAccessorBufferWriteMarker.End(); - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); accessor.BufferView = ExportBufferView(byteOffset, byteLength, sizeof(float) * 3); @@ -807,7 +807,7 @@ private AccessorId ExportSparseAccessor(AccessorId baseAccessor, Vector3[] baseD { exportSparseAccessorMarker.Begin(); - uint dataCount = (uint) arr.Length; + long dataCount = (long)arr.Length; if (dataCount == 0) { throw new Exception("Accessors can not have a count of 0."); @@ -856,7 +856,7 @@ private AccessorId ExportSparseAccessor(AccessorId baseAccessor, Vector3[] baseD } // we need to calculate the min/max of the entire new data array - uint count = (uint) arr.Length; + long count = (long)arr.Length; var firstElement = baseData != null ? (baseData[0] + arr[0]) : arr[0]; float minX = firstElement.x; @@ -901,7 +901,7 @@ private AccessorId ExportSparseAccessor(AccessorId baseAccessor, Vector3[] baseD // write indices AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffsetIndices = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffsetIndices = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); // Debug.Log("Storing " + indices.Count + " sparse indices + values"); @@ -910,7 +910,7 @@ private AccessorId ExportSparseAccessor(AccessorId baseAccessor, Vector3[] baseD _bufferWriter.Write(index); } - uint byteLengthIndices = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffsetIndices, 4); + long byteLengthIndices = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffsetIndices, 4); sparse.Indices = new AccessorSparseIndices(); // TODO should be properly using the smallest possible component type @@ -919,7 +919,7 @@ private AccessorId ExportSparseAccessor(AccessorId baseAccessor, Vector3[] baseD // write values AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); exportAccessorBufferWriteMarker.Begin(); foreach (var i in indices) @@ -931,7 +931,7 @@ private AccessorId ExportSparseAccessor(AccessorId baseAccessor, Vector3[] baseD } exportAccessorBufferWriteMarker.End(); - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); sparse.Values = new AccessorSparseValues(); sparse.Values.BufferView = ExportBufferView(byteOffset, byteLength); @@ -956,7 +956,7 @@ private AccessorId ExportAccessor(Vector4[] arr) exportAccessorMarker.Begin(); exportAccessorVector4ArrayMarker.Begin(); - uint count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -1027,7 +1027,7 @@ private AccessorId ExportAccessor(Vector4[] arr) accessor.Max = new List { maxX, maxY, maxZ, maxW }; AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); exportAccessorBufferWriteMarker.Begin(); #if USE_FAST_BINARY_WRITER @@ -1043,7 +1043,7 @@ private AccessorId ExportAccessor(Vector4[] arr) #endif exportAccessorBufferWriteMarker.End(); - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); accessor.BufferView = ExportBufferView(byteOffset, byteLength); @@ -1065,7 +1065,7 @@ private AccessorId ExportAccessor(Color[] arr, bool exportAlphaChannel) exportAccessorMarker.Begin(); exportAccessorColorArrayMarker.Begin(); - uint count = (uint)arr.Length; + long count = arr.Length; if (count == 0) { @@ -1136,7 +1136,7 @@ private AccessorId ExportAccessor(Color[] arr, bool exportAlphaChannel) } AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); if(exportAlphaChannel) { @@ -1158,7 +1158,7 @@ private AccessorId ExportAccessor(Color[] arr, bool exportAlphaChannel) } } - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); accessor.BufferView = ExportBufferView(byteOffset, byteLength); @@ -1177,13 +1177,13 @@ private AccessorId ExportAccessor(Color[] arr, bool exportAlphaChannel) public BufferViewId ExportBufferView(byte[] bytes) { AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); _bufferWriter.Write(bytes); - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); - return ExportBufferView((uint)byteOffset, (uint)byteLength); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); + return ExportBufferView(byteOffset, byteLength); } - private BufferViewId ExportBufferView(uint byteOffset, uint byteLength, uint byteStride = 0) + private BufferViewId ExportBufferView(long byteOffset, long byteLength, uint byteStride = 0) { var bufferView = new BufferView { diff --git a/Runtime/Scripts/SceneExporter/ExporterTextures.cs b/Runtime/Scripts/SceneExporter/ExporterTextures.cs index f624dd443..6ff040f10 100644 --- a/Runtime/Scripts/SceneExporter/ExporterTextures.cs +++ b/Runtime/Scripts/SceneExporter/ExporterTextures.cs @@ -544,7 +544,7 @@ private ImageId ExportImageInternalBuffer(UniqueTexture uniqueTexture, string te image.MimeType = PNGMimeType; AlignToBoundary(_bufferWriter.BaseStream, 0x00); - uint byteOffset = CalculateAlignment((uint)_bufferWriter.BaseStream.Position, 4); + long byteOffset = CalculateAlignment(_bufferWriter.BaseStream.Position, 4); bool wasAbleToExport = false; bool textureHasAlpha = true; @@ -703,8 +703,8 @@ private ImageId ExportImageInternalBuffer(UniqueTexture uniqueTexture, string te // Debug.LogWarning("Validation Warning: " + "Image has non-power-of-two dimensions: " + texture.width + "x" + texture.height + ".", texture); // } - uint byteLength = CalculateAlignment((uint)_bufferWriter.BaseStream.Position - byteOffset, 4); - image.BufferView = ExportBufferView((uint)byteOffset, (uint)byteLength); + long byteLength = CalculateAlignment(_bufferWriter.BaseStream.Position - byteOffset, 4); + image.BufferView = ExportBufferView(byteOffset, byteLength); if (ExportNames) { diff --git a/Runtime/Scripts/SceneImporter/ImporterMeshes.cs b/Runtime/Scripts/SceneImporter/ImporterMeshes.cs index 0d6f34a98..e317a4d37 100644 --- a/Runtime/Scripts/SceneImporter/ImporterMeshes.cs +++ b/Runtime/Scripts/SceneImporter/ImporterMeshes.cs @@ -181,9 +181,9 @@ private static uint[] CalculateSubMeshVertexOffset(GLTFMesh mesh, out uint total if (!accessorIds.ContainsKey(acc.Id)) { accessorIds.Add(acc.Id, acc); - totalVertCount += acc.Value.Count; + totalVertCount += (uint)acc.Value.Count; vOffset = lastVertOffset; - lastVertOffset += acc.Value.Count; + lastVertOffset += (uint)acc.Value.Count; } vertOffsetBySubMesh[primIndex] = vOffset; @@ -850,7 +850,7 @@ protected virtual async Task ConstructMeshTargetsPrepareBuffers(MeshPrimitive pr { AccessorId = targetAttribute.Value, bufferData = _assetCache.BufferCache[bufferID].bufferData, - Offset = (uint)_assetCache.BufferCache[bufferID].ChunkDataOffset + Offset = _assetCache.BufferCache[bufferID].ChunkDataOffset }; // if this buffer isn't sparse, we're done here @@ -910,7 +910,7 @@ protected virtual void ConstructMeshTargets(MeshPrimitive primitive, int meshInd { AccessorId = targetAttribute.Value, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkDataOffset + Offset = bufferData.ChunkDataOffset }; GLTFHelpers.LoadBufferView(sparseValues.AccessorId.Value.Sparse.Values.BufferView.Value, sparseValues.Offset, sparseValues.bufferData, out NativeArray bufferViewCache1); @@ -922,7 +922,7 @@ protected virtual void ConstructMeshTargets(MeshPrimitive primitive, int meshInd { AccessorId = targetAttribute.Value, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkDataOffset, + Offset = bufferData.ChunkDataOffset, }; GLTFHelpers.LoadBufferView(sparseIndices.AccessorId.Value.Sparse.Indices.BufferView.Value, sparseIndices.Offset, sparseIndices.bufferData, out NativeArray bufferViewCache2); @@ -1218,7 +1218,7 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv { AccessorId = attributePair.Value, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkDataOffset + Offset = bufferData.ChunkDataOffset }; } @@ -1233,7 +1233,7 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv { AccessorId = attributePair.Value, bufferData = sparseBufferData.bufferData, - Offset = (uint)sparseBufferData.ChunkDataOffset + Offset = sparseBufferData.ChunkDataOffset }; var sparseIndicesBufferId = sparse.Indices.BufferView.Value.Buffer; @@ -1242,7 +1242,7 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv { AccessorId = attributePair.Value, bufferData = sparseIndicesBufferData.bufferData, - Offset = (uint)sparseIndicesBufferData.ChunkDataOffset + Offset = sparseIndicesBufferData.ChunkDataOffset }; primData.SparseAccessors[attributePair.Key] = (sparseIndices, sparseValues); @@ -1261,7 +1261,7 @@ protected virtual async Task ConstructPrimitiveAttributes(MeshPrimitive primitiv { AccessorId = primitive.Indices, bufferData = bufferData.bufferData, - Offset = (uint)bufferData.ChunkDataOffset + Offset = bufferData.ChunkDataOffset }; } } @@ -1281,7 +1281,7 @@ protected void ConvertAttributeAccessorsToUnityTypes( uint vertexCount = 0; if (meshAttributes.TryGetValue(SemanticProperties.POSITION, out var attribute)) { - vertexCount = attribute.AccessorId.Value.Count; + vertexCount = (uint)attribute.AccessorId.Value.Count; } int[] indices = null; From 2b24e89bedcb4c086ca04622ffe98de1bbe840bc Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Tue, 23 Jun 2026 03:18:53 -0700 Subject: [PATCH 4/5] Support importing GLB version 3 files --- .../Plugins/GLTFSerialization/GLBBuilder.cs | 127 ++++++++------ .../Plugins/GLTFSerialization/GLBObject.cs | 7 +- .../Plugins/GLTFSerialization/GLTFParser.cs | 165 ++++++++++++------ Runtime/Scripts/GLTFSceneImporter.cs | 4 +- 4 files changed, 195 insertions(+), 108 deletions(-) diff --git a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs index 49f9ffa19..54fe045ad 100644 --- a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs +++ b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs @@ -15,8 +15,9 @@ public static class GLBBuilder /// The glTF root to turn into a GLBObject /// Output stream to write the GLB to /// Loader for loading external components from GLTFRoot. The loader will receive uris and return the stream to the resource + /// The GLB binary format version to output. /// A constructed GLBObject - private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, Func loader) + private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, Func loader, uint glbVersion = 2) { if (root == null) throw new ArgumentNullException(nameof(root)); if (glbOutStream == null) throw new ArgumentNullException(nameof(glbOutStream)); @@ -26,27 +27,28 @@ private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, F { root.Serialize(sw, true); sw.Flush(); - - long proposedFileLength = gltfJsonStream.Length + GLBHeader.GLB2_FILE_HEADER_SIZE + GLBHeader.GLB2_CHUNK_HEADER_SIZE; - if (gltfJsonStream.Length > uint.MaxValue) + GLBHeader glbHeader = new GLBHeader + { + Version = glbVersion, + }; + long proposedFileLength = gltfJsonStream.Length + glbHeader.GetFileHeaderSize() + glbHeader.GetChunkHeaderSize(); + // If the file length would be too big for GLB version 2, automatically upgrade to GLB version 3. + if (glbHeader.Version == 2 && proposedFileLength > uint.MaxValue) { - throw new ArgumentException("Serialized root cannot exceed uint.MaxValue", nameof(root)); + glbHeader.Version = 3; + proposedFileLength = gltfJsonStream.Length + glbHeader.GetFileHeaderSize() + glbHeader.GetChunkHeaderSize(); } - uint proposedLengthAsUint = (uint)proposedFileLength; - glbOutStream.SetLength(proposedLengthAsUint); + glbHeader.FileLength = proposedFileLength; + glbOutStream.SetLength(proposedFileLength); GLBObject glbObject = new GLBObject { - Header = new GLBHeader - { - FileLength = proposedLengthAsUint, - Version = 2 - }, + Header = glbHeader, Root = root, Stream = glbOutStream, JsonChunkInfo = new GLBChunkInfo { - Length = (uint)gltfJsonStream.Length, - StartPosition = GLBHeader.GLB2_FILE_HEADER_SIZE, + Length = gltfJsonStream.Length, + StartPosition = glbHeader.GetFileHeaderSize(), Type = GLBChunkFormat.JSON } }; @@ -91,7 +93,7 @@ public static GLBObject ConstructFromGLB(GLTFRoot root, Stream inputGLBStream, S inputGLBStream.Position = 4 + inputGLBStreamStartPosition; GLBHeader glbHeader = GLTFParser.ParseGLBHeader(inputGLBStream); - inputGLBStream.Position = GLBHeader.GLB2_FILE_HEADER_SIZE + inputGLBStreamStartPosition; + inputGLBStream.Position = glbHeader.GetFileHeaderSize() + inputGLBStreamStartPosition; List allChunks = GLTFParser.FindChunks(inputGLBStream); GLBChunkInfo jsonChunkInfo = new GLBChunkInfo { @@ -167,25 +169,29 @@ public static GLBObject ConstructFromStream(Stream inStream, Stream glbOutStream private static GLBObject _ConstructFromEmptyStream(Stream inStream, long streamStartPosition) { + // Only support GLB version 2 for the empty stream case. + GLBHeader glbHeader = new GLBHeader + { + Version = 2 + }; + glbHeader.FileLength = glbHeader.GetFileHeaderSize(); GLBObject glbObject = new GLBObject { Stream = inStream, + Header = glbHeader, JsonChunkInfo = new GLBChunkInfo { Length = 0, - StartPosition = GLBHeader.GLB2_FILE_HEADER_SIZE, - Type = GLBChunkFormat.JSON + StartPosition = glbHeader.GetFileHeaderSize(), + Type = GLBChunkFormat.JSON, + Encoding = 0 }, BinaryChunkInfo = new GLBChunkInfo { Length = 0, - StartPosition = GLBHeader.GLB2_FILE_HEADER_SIZE + GLBHeader.GLB2_CHUNK_HEADER_SIZE, - Type = GLBChunkFormat.BIN - }, - Header = new GLBHeader - { - FileLength = GLBHeader.GLB2_FILE_HEADER_SIZE, - Version = 2 + StartPosition = glbHeader.GetFileHeaderSize() + glbHeader.GetChunkHeaderSize(), + Type = GLBChunkFormat.BIN, + Encoding = 0 }, StreamStartPosition = streamStartPosition }; @@ -198,7 +204,6 @@ private static GLBObject _ConstructFromEmptyStream(Stream inStream, long streamS /// The GLBObject stream will be updated to be the output stream. Callers are responsible for handling Stream lifetime /// /// The GLB to flush to the output stream and update - /// Optional root to replace the one in the glb /// A GLBObject that is based upon outStream public static void UpdateStream(GLBObject glb) { @@ -210,12 +215,15 @@ public static void UpdateStream(GLBObject glb) { glb.Root.Serialize(sw, true); // todo: this could out of memory exception sw.Flush(); - - if (gltfJsonStream.Length > int.MaxValue) + GLBHeader glbHeader = glb.Header; // Be sure to write this back in if it was updated. + // If the file length would be too big for GLB version 2, automatically upgrade to GLB version 3. + if (glbHeader.Version == 2 && gltfJsonStream.Length > uint.MaxValue) { - // todo: make this a non generic exception - throw new Exception("JSON chunk of GLB has exceeded maximum allowed size (4 GB)"); + glbHeader.Version = 3; + glb.Header = glbHeader; } + long fileHeaderSize = glbHeader.GetFileHeaderSize(); + long chunkHeaderSize = glbHeader.GetChunkHeaderSize(); // realloc of out of space if (glb.JsonChunkInfo.Length < gltfJsonStream.Length) @@ -229,19 +237,23 @@ public static void UpdateStream(GLBObject glb) // we have not yet initialized a json chunk before if (glb.JsonChunkInfo.Length == 0) { - amountToAddToFile += GLBHeader.GLB2_CHUNK_HEADER_SIZE; - glb.SetJsonChunkStartPosition(GLBHeader.GLB2_FILE_HEADER_SIZE); + amountToAddToFile += fileHeaderSize; + glb.SetJsonChunkStartPosition(chunkHeaderSize); } - // new proposed length = proposedJsonBufferSize - currentJsonBufferSize + totalFileLength - long proposedFileLength = amountToAddToFile + glb.Header.FileLength; - if (proposedFileLength > uint.MaxValue) + long proposedFileLength = amountToAddToFile + glbHeader.FileLength; + // If the file length would be too big for GLB version 2, automatically upgrade to GLB version 3. + if (glbHeader.Version == 2 && proposedFileLength > uint.MaxValue) { - throw new Exception("GLB has exceeded max allowed size (4 GB)"); + amountToAddToFile -= fileHeaderSize; + glbHeader.Version = 3; + glb.Header = glbHeader; + fileHeaderSize = glbHeader.GetFileHeaderSize(); + chunkHeaderSize = glbHeader.GetChunkHeaderSize(); + amountToAddToFile += fileHeaderSize; + glb.SetJsonChunkStartPosition(chunkHeaderSize); } - uint proposedLengthAsUint = (uint)proposedFileLength; - try { glb.Stream.SetLength(proposedFileLength); @@ -256,14 +268,13 @@ public static void UpdateStream(GLBObject glb) throw; } - long newBinaryChunkDataStartPosition = - GLBHeader.GLB2_FILE_HEADER_SIZE + GLBHeader.GLB2_CHUNK_HEADER_SIZE + proposedJsonChunkLength; + long newBinaryChunkDataStartPosition = fileHeaderSize + chunkHeaderSize + proposedJsonChunkLength; glb.Stream.Position = glb.BinaryChunkInfo.StartPosition; glb.SetBinaryChunkStartPosition(newBinaryChunkDataStartPosition); if (glb.BinaryChunkInfo.Length > 0) { - long lengthToCopy = glb.BinaryChunkInfo.Length + GLBHeader.GLB2_CHUNK_HEADER_SIZE; + long lengthToCopy = glb.BinaryChunkInfo.Length + chunkHeaderSize; // todo: we need to be able to copy while doing it with smaller buffers. Also int is smaller than uint, so this is not standards compliant. glb.Stream.CopyToSelf((int)newBinaryChunkDataStartPosition, @@ -271,8 +282,8 @@ public static void UpdateStream(GLBObject glb) } // write out new GLB length - glb.SetFileLength(proposedLengthAsUint); - WriteHeader(glb.Stream, glb.Header, glb.StreamStartPosition); + glb.SetFileLength(proposedFileLength); + WriteHeader(glb.Stream, glbHeader, glb.StreamStartPosition); // write out new JSON header glb.SetJsonChunkLength(proposedJsonChunkLength); @@ -280,7 +291,7 @@ public static void UpdateStream(GLBObject glb) } // clear the buffer - glb.Stream.Position = glb.JsonChunkInfo.StartPosition + GLBHeader.GLB2_CHUNK_HEADER_SIZE; + glb.Stream.Position = glb.JsonChunkInfo.StartPosition + chunkHeaderSize; long amountToCopy = glb.JsonChunkInfo.Length; while (amountToCopy != 0) { @@ -293,7 +304,7 @@ public static void UpdateStream(GLBObject glb) // write new JSON data gltfJsonStream.Position = 0; - glb.Stream.Position = glb.JsonChunkInfo.StartPosition + GLBHeader.GLB2_CHUNK_HEADER_SIZE; + glb.Stream.Position = glb.JsonChunkInfo.StartPosition + chunkHeaderSize; gltfJsonStream.CopyTo(glb.Stream); glb.Stream.Flush(); } @@ -311,10 +322,10 @@ public static void UpdateStream(GLBObject glb) public static BufferViewId AddBinaryData(GLBObject glb, Stream binaryData, bool createBufferView = true, long streamStartPosition = 0, string bufferViewName = null) { if (glb == null) throw new ArgumentNullException(nameof(glb)); - if(glb.Root == null && bufferViewName == null) throw new ArgumentException("glb Root and new root cannot be null", nameof(glb)); - if(glb.Stream == null) throw new ArgumentException("glb Stream cannot be null", nameof(glb)); - if(binaryData == null) throw new ArgumentNullException(nameof(binaryData)); - if(binaryData.Length > uint.MaxValue) throw new ArgumentException("Stream cannot be larger than uint.MaxValue", nameof(binaryData)); + if (glb.Root == null && bufferViewName == null) throw new ArgumentException("glb Root and new root cannot be null", nameof(glb)); + if (glb.Stream == null) throw new ArgumentException("glb Stream cannot be null", nameof(glb)); + if (binaryData == null) throw new ArgumentNullException(nameof(binaryData)); + if (glb.Header.Version == 2 && binaryData.Length > uint.MaxValue) throw new ArgumentException("Stream cannot be larger than uint.MaxValue", nameof(binaryData)); return _AddBinaryData(glb, binaryData, createBufferView, streamStartPosition, bufferViewName); } @@ -328,12 +339,13 @@ private static BufferViewId _AddBinaryData(GLBObject glb, Stream binaryData, boo long newBinaryBufferSize = glb.BinaryChunkInfo.Length + blobLength; long newGLBSize = glb.Header.FileLength + blobLength; long blobWritePosition = glb.Header.FileLength; + long chunkHeaderSize = glb.Header.GetChunkHeaderSize(); // there was an existing file that had no binary chunk info previously if (glb.BinaryChunkInfo.Length == 0) { - newGLBSize += GLBHeader.GLB2_CHUNK_HEADER_SIZE; - blobWritePosition += GLBHeader.GLB2_CHUNK_HEADER_SIZE; + newGLBSize += chunkHeaderSize; + blobWritePosition += chunkHeaderSize; glb.SetBinaryChunkStartPosition(glb.Header.FileLength); // if 0, then appends chunk info at the end } @@ -397,7 +409,8 @@ public static void MergeGLBs(GLBObject mergeTo, GLBObject mergeFrom) int previousBufferViewsCount = mergeTo.Root.BufferViews?.Count ?? 0; long previousBufferSize = mergeTo.BinaryChunkInfo.Length; GLTFHelpers.MergeGLTF(mergeTo.Root, mergeFrom.Root); - _AddBinaryData(mergeTo, mergeFrom.Stream, false, mergeFrom.BinaryChunkInfo.StartPosition + GLBHeader.GLB2_CHUNK_HEADER_SIZE); + long toChunkHeaderSize = mergeTo.Header.GetChunkHeaderSize(); + _AddBinaryData(mergeTo, mergeFrom.Stream, false, mergeFrom.BinaryChunkInfo.StartPosition + toChunkHeaderSize); long bufferSizeDiff = mergeTo.BinaryChunkInfo.Length - previousBufferSize; // calculate buffer size change to update the byte offsets of the appended buffer views @@ -438,7 +451,7 @@ public static void RemoveBinaryData(GLBObject glb, BufferViewId bufferViewId) --bufferView.Buffer.Id; } - glb.SetFileLength(glb.Header.FileLength - GLBHeader.GLB2_CHUNK_HEADER_SIZE); + glb.SetFileLength(glb.Header.FileLength - glb.Header.GetChunkHeaderSize()); } else { @@ -510,7 +523,15 @@ private static void WriteHeader(Stream stream, GLBHeader glbHeader, long streamS stream.Position = streamStartPosition; byte[] magicNumber = BitConverter.GetBytes(GLBHeader.GLTF_MAGIC_NUMBER); byte[] version = BitConverter.GetBytes(glbHeader.Version); - byte[] length = BitConverter.GetBytes(glbHeader.FileLength); + byte[] length; + if (glbHeader.Version == 2) + { + length = BitConverter.GetBytes((uint)glbHeader.FileLength); + } + else + { + length = BitConverter.GetBytes((ulong)glbHeader.FileLength); + } stream.Write(magicNumber, 0, magicNumber.Length); stream.Write(version, 0, version.Length); diff --git a/Runtime/Plugins/GLTFSerialization/GLBObject.cs b/Runtime/Plugins/GLTFSerialization/GLBObject.cs index db5b7f085..0cdf12559 100644 --- a/Runtime/Plugins/GLTFSerialization/GLBObject.cs +++ b/Runtime/Plugins/GLTFSerialization/GLBObject.cs @@ -18,8 +18,10 @@ public struct GLBHeader public uint Version { get; set; } public long FileLength { get; set; } - public static readonly uint GLB2_FILE_HEADER_SIZE = 12; - public static readonly uint GLB2_CHUNK_HEADER_SIZE = 8; + public long GetFileHeaderSize() => Version == 2 ? 12 : 16; + public long GetChunkHeaderSize() => Version == 2 ? 8 : 16; + public long GetAlignment() => Version == 2 ? 4 : 8; + public long GetAlignmentBitmask() => Version == 2 ? 3 : 7; /// /// ASCII string "glTF" in little-endian order. @@ -35,6 +37,7 @@ public struct GLBChunkInfo public long StartPosition; public long Length; public GLBChunkFormat Type; + public uint Encoding; } /// diff --git a/Runtime/Plugins/GLTFSerialization/GLTFParser.cs b/Runtime/Plugins/GLTFSerialization/GLTFParser.cs index 3b2f64673..b753b82b7 100644 --- a/Runtime/Plugins/GLTFSerialization/GLTFParser.cs +++ b/Runtime/Plugins/GLTFSerialization/GLTFParser.cs @@ -15,7 +15,8 @@ public static void ParseJson(Stream stream, out GLTFRoot gltfRoot, long startPos // Check for binary format magic bytes if (isGLB) { - ParseJsonChunkAndFileHeader(stream, startPosition); + GLBChunkInfo jsonChunkInfo = ParseJsonChunkHeader(stream, startPosition); + ThrowIfUnsupportedChunkEncoding(jsonChunkInfo); } else { @@ -26,56 +27,70 @@ public static void ParseJson(Stream stream, out GLTFRoot gltfRoot, long startPos gltfRoot.IsGLB = isGLB; } - // todo: this needs reimplemented. There is no such thing as a binary chunk index, and the chunk may not be in 0, 1, 2 order - // Moves stream position to binary chunk location + /// + /// Moves stream position to the data inside of the binary chunk with the given index, after the chunk header. + /// Throws an exception if the headers are invalid or the chunk index is beyond the number of chunks in the stream. + /// public static GLBChunkInfo SeekToBinaryChunkData(Stream stream, int binaryChunkIndex, long startPosition = 0) { stream.Position = startPosition + 4; // Start after "glTF" magic number. - GLBHeader glbHeader = ParseGLBHeader(stream); - uint chunkOffset = 12; // sizeof(GLBHeader) + magic number - uint chunkLength = 0; - for (int i = 0; i < binaryChunkIndex + 2; ++i) - { - chunkOffset += chunkLength; - stream.Position = chunkOffset; - chunkLength = GetUInt32(stream); - chunkOffset += 8; // to account for chunk length (4 bytes) and type (4 bytes) - } - - // Load Binary Chunk - if (chunkOffset + chunkLength <= glbHeader.FileLength) + GLBHeader glbHeader = ParseGLBHeader(stream); // 4 -> 12 or 16 + long alignmentBitmask = glbHeader.GetAlignmentBitmask(); + long chunkHeaderSize = glbHeader.GetChunkHeaderSize(); + GLBChunkInfo chunkInfo = new GLBChunkInfo(); + for (int i = 0; i < binaryChunkIndex + 1; i++) { - GLBChunkFormat chunkType = (GLBChunkFormat)GetUInt32(stream); - if (chunkType != GLBChunkFormat.BIN) + if (i > 0) { - throw new GLTFHeaderInvalidException("Second chunk must be of type BIN if present"); + long paddedChunkLength = (chunkInfo.Length + alignmentBitmask) & ~alignmentBitmask; // Align to 4 or 8 bytes. + stream.Position += paddedChunkLength; // Seek over the previous chunk's data plus padding. } - - return new GLBChunkInfo + if (stream.Position + chunkHeaderSize > stream.Length) + { + throw new GLTFHeaderInvalidException("There are no more chunks in the stream to read. The GLB file only has " + i + " chunks, but the requested chunk index was " + binaryChunkIndex + "."); + } + chunkInfo.StartPosition = stream.Position; + // Binary format version 2 and 3 have different chunk header sizes and field order. + if (glbHeader.Version == 2) + { + chunkInfo.Length = GetUInt32(stream); + chunkInfo.Type = (GLBChunkFormat)GetUInt32(stream); + chunkInfo.Encoding = 0; + } + else if (glbHeader.Version == 3) + { + chunkInfo.Type = (GLBChunkFormat)GetUInt32(stream); + chunkInfo.Encoding = GetUInt32(stream); + chunkInfo.Length = (long)GetUInt64(stream); + } + else + { + throw new GLTFHeaderInvalidException("Unsupported glTF binary format version " + glbHeader.Version + ". Only versions 2 and 3 are supported."); + } + if (stream.Position + chunkInfo.Length > stream.Length) { - StartPosition = stream.Position - GLBHeader.GLB2_CHUNK_HEADER_SIZE, - Length = chunkLength, - Type = chunkType - }; + throw new GLTFHeaderInvalidException("Chunk length exceeds stream length."); + } } - - - // Be aware that File length does not match header when MeshOpt compression is used! - //throw new GLTFHeaderInvalidException("File length does not match chunk header."); - - return new GLBChunkInfo - { - StartPosition = stream.Position - GLBHeader.GLB2_CHUNK_HEADER_SIZE, - Length = chunkLength, - Type = GLBChunkFormat.BIN - }; + return chunkInfo; } public static GLBHeader ParseGLBHeader(Stream stream) { - uint version = GetUInt32(stream); // 4 - uint length = GetUInt32(stream); // 8 - + uint version = GetUInt32(stream); // 4 -> 8 + long length; + if (version == 2) + { + length = GetUInt32(stream); // 8 -> 12 + } + else if (version == 3) + { + length = (long)GetUInt64(stream); // 8 -> 16 + } + else + { + throw new GLTFHeaderInvalidException("Unsupported glTF binary format version " + version + ". Only versions 2 and 3 are supported."); + } return new GLBHeader { Version = version, @@ -88,45 +103,61 @@ public static bool IsGLB(Stream stream) return GetUInt32(stream) == GLBHeader.GLTF_MAGIC_NUMBER; } - public static GLBChunkInfo ParseChunkInfo(Stream stream) + public static GLBChunkInfo ParseChunkInfo(Stream stream, uint glbVersion) { GLBChunkInfo chunkInfo = new GLBChunkInfo { StartPosition = stream.Position }; - - chunkInfo.Length = GetUInt32(stream); // 12 - chunkInfo.Type = (GLBChunkFormat)GetUInt32(stream); // 16 + // Binary format version 2 and 3 have different chunk header sizes and field order. + if (glbVersion == 2) + { + chunkInfo.Length = GetUInt32(stream); + chunkInfo.Type = (GLBChunkFormat)GetUInt32(stream); + chunkInfo.Encoding = 0; + } + else if (glbVersion == 3) + { + chunkInfo.Type = (GLBChunkFormat)GetUInt32(stream); + chunkInfo.Encoding = GetUInt32(stream); + chunkInfo.Length = (long)GetUInt64(stream); + } + else + { + throw new GLTFHeaderInvalidException("Unsupported glTF binary format version " + glbVersion + ". Only versions 2 and 3 are supported."); + } return chunkInfo; } public static List FindChunks(Stream stream, long startPosition = 0) { stream.Position = startPosition + 4; // Start after "glTF" magic number. - ParseGLBHeader(stream); + GLBHeader glbHeader = ParseGLBHeader(stream); + long alignmentBitmask = glbHeader.GetAlignmentBitmask(); List allChunks = new List(); // we only need to search for top two chunks (the JSON and binary chunks are guaranteed to be the top two chunks) // other chunks can be in the file but we do not care about them for (int i = 0; i < 2; ++i) { - if (stream.Position == stream.Length) + if (stream.Position >= stream.Length) { break; } - GLBChunkInfo chunkInfo = ParseChunkInfo(stream); + GLBChunkInfo chunkInfo = ParseChunkInfo(stream, glbHeader.Version); allChunks.Add(chunkInfo); - stream.Position += chunkInfo.Length; + long paddedChunkLength = (chunkInfo.Length + alignmentBitmask) & ~alignmentBitmask; // Align to 4 or 8 bytes. + stream.Position += paddedChunkLength; } return allChunks; } - private static void ParseJsonChunkAndFileHeader(Stream stream, long startPosition) + private static GLBChunkInfo ParseJsonChunkHeader(Stream stream, long startPosition) { - GLBHeader glbHeader = ParseGLBHeader(stream); // 4, 8 - if (glbHeader.Version != 2) + GLBHeader glbHeader = ParseGLBHeader(stream); // 4 -> 12 or 16 + if (glbHeader.Version != 2 && glbHeader.Version != 3) { throw new GLTFHeaderInvalidException("Unsupported glTF version"); }; @@ -136,11 +167,41 @@ private static void ParseJsonChunkAndFileHeader(Stream stream, long startPositio throw new GLTFHeaderInvalidException("File length does not match GLB file header declared length."); } - GLBChunkInfo chunkInfo = ParseChunkInfo(stream); - if (chunkInfo.Type != GLBChunkFormat.JSON) + GLBChunkInfo jsonChunkInfo = ParseChunkInfo(stream, glbHeader.Version); // 12 -> 20 or 16 -> 32 + if (jsonChunkInfo.Type != GLBChunkFormat.JSON) { throw new GLTFHeaderInvalidException("First chunk must be of type JSON"); } + return jsonChunkInfo; + } + + public static void ThrowIfUnsupportedChunkEncoding(GLBChunkInfo chunkInfo) + { + // Only support plainly encoded chunks for now. If we want to support compressed or encrypted + // chunks, we need to decompress or decrypt them at the call sites of this function. + if (chunkInfo.Encoding != 0) + { + throw new GLTFHeaderInvalidException("Unsupported encoding '" + UInt32ToAsciiString(chunkInfo.Encoding) + "' (0x" + chunkInfo.Encoding.ToString("X") + ") found. Only plain encoding (0x00000000) is supported."); + } + } + + private static string UInt32ToAsciiString(uint number) + { + string str = ""; + for (int i = 0; i < 4; i++) + { + byte lowByte = (byte)number; + if (lowByte > 0x1F && lowByte < 0x7F) + { + str += (char)lowByte; + } + else + { + str += '?'; + } + number >>= 8; + } + return str; } private static uint GetUInt32(Stream stream) diff --git a/Runtime/Scripts/GLTFSceneImporter.cs b/Runtime/Scripts/GLTFSceneImporter.cs index 4dbdf9895..2fa707bb0 100644 --- a/Runtime/Scripts/GLTFSceneImporter.cs +++ b/Runtime/Scripts/GLTFSceneImporter.cs @@ -1527,7 +1527,9 @@ protected virtual async Task ConstructScene(GLTFScene scene, bool showSceneObj, protected virtual BufferCacheData ConstructBufferFromGLB(int bufferIndex) { - GLTFParser.SeekToBinaryChunkData(_gltfStream.Stream, bufferIndex, _gltfStream.StartPosition); // sets stream to correct start position + int binaryChunkIndex = bufferIndex + 1; // Chunk 0 is the JSON chunk, chunk 1 is buffer 0. + GLBChunkInfo chunkInfo = GLTFParser.SeekToBinaryChunkData(_gltfStream.Stream, binaryChunkIndex, _gltfStream.StartPosition); // sets stream to correct start position + GLTFParser.ThrowIfUnsupportedChunkEncoding(chunkInfo); return new BufferCacheData { Stream = _gltfStream.Stream, From 8c54b8b33a37a7b483f18d1ab78adb63e37ba926 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Tue, 23 Jun 2026 05:21:03 -0700 Subject: [PATCH 5/5] Support exporting GLB version 3 files --- Editor/Scripts/GLTFExportMenu.cs | 5 +- .../Plugins/GLTFSerialization/GLBBuilder.cs | 10 +-- Runtime/Scripts/GLTFSceneExporter.cs | 75 ++++++++++++++----- Runtime/Scripts/GLTFSettings.cs | 1 + Runtime/Scripts/Timeline/GLTFRecorder.cs | 2 +- 5 files changed, 67 insertions(+), 26 deletions(-) diff --git a/Editor/Scripts/GLTFExportMenu.cs b/Editor/Scripts/GLTFExportMenu.cs index c64c6dcaf..bf1877c71 100644 --- a/Editor/Scripts/GLTFExportMenu.cs +++ b/Editor/Scripts/GLTFExportMenu.cs @@ -509,11 +509,14 @@ private static bool Export(ExportBatch batch, bool binary, bool askForLocation) { var sceneName = batch.sceneName; var ext = binary ? ".glb" : ".gltf"; + bool allowExporting64BitGLB = settings.AllowExporting64BitGLB; var resultFile = GLTFSceneExporter.GetFileName(path, sceneName, ext); settings.SaveFolderPath = path; + // Prefer saving as GLB version 2 for compatibility. + int glbVersion = allowExporting64BitGLB ? -1 : 2; // -1 means "auto". if (binary) - exporter.SaveGLB(path, sceneName); + exporter.SaveGLB(path, sceneName, glbVersion); else exporter.SaveGLTFandBin(path, sceneName); diff --git a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs index 54fe045ad..d4e51cc15 100644 --- a/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs +++ b/Runtime/Plugins/GLTFSerialization/GLBBuilder.cs @@ -17,7 +17,7 @@ public static class GLBBuilder /// Loader for loading external components from GLTFRoot. The loader will receive uris and return the stream to the resource /// The GLB binary format version to output. /// A constructed GLBObject - private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, Func loader, uint glbVersion = 2) + private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, Func loader, int glbVersion) { if (root == null) throw new ArgumentNullException(nameof(root)); if (glbOutStream == null) throw new ArgumentNullException(nameof(glbOutStream)); @@ -29,11 +29,11 @@ private static GLBObject ConstructFromGLTF(GLTFRoot root, Stream glbOutStream, F sw.Flush(); GLBHeader glbHeader = new GLBHeader { - Version = glbVersion, + Version = (uint)(glbVersion == -1 ? 2 : glbVersion) }; long proposedFileLength = gltfJsonStream.Length + glbHeader.GetFileHeaderSize() + glbHeader.GetChunkHeaderSize(); - // If the file length would be too big for GLB version 2, automatically upgrade to GLB version 3. - if (glbHeader.Version == 2 && proposedFileLength > uint.MaxValue) + // If automatic, and the file length would be too big for GLB version 2, automatically upgrade to GLB version 3. + if (glbVersion == -1 && proposedFileLength > uint.MaxValue) { glbHeader.Version = 3; proposedFileLength = gltfJsonStream.Length + glbHeader.GetFileHeaderSize() + glbHeader.GetChunkHeaderSize(); @@ -158,7 +158,7 @@ public static GLBObject ConstructFromStream(Stream inStream, Stream glbOutStream } if (!root.IsGLB) { - return ConstructFromGLTF(root, glbOutStream, loader); + return ConstructFromGLTF(root, glbOutStream, loader, 2); } return ConstructFromGLB(root, inStream, glbOutStream, streamStartPosition); diff --git a/Runtime/Scripts/GLTFSceneExporter.cs b/Runtime/Scripts/GLTFSceneExporter.cs index 7312c80a8..61a5ff7d0 100644 --- a/Runtime/Scripts/GLTFSceneExporter.cs +++ b/Runtime/Scripts/GLTFSceneExporter.cs @@ -726,7 +726,7 @@ public GLTFRoot GetRoot() /// /// File path for saving the binary file /// The name of the GLTF file - public void SaveGLB(string path, string fileName) + public void SaveGLB(string path, string fileName, int glbVersion) { var fullPath = GetFileName(path, fileName, ".glb"); var dirName = Path.GetDirectoryName(fullPath); @@ -736,7 +736,7 @@ public void SaveGLB(string path, string fileName) using (FileStream glbFile = new FileStream(fullPath, FileMode.Create)) { - SaveGLBToStream(glbFile, fileName); + SaveGLBToStream(glbFile, fileName, glbVersion); } if (!_shouldUseInternalBufferForImages) @@ -751,12 +751,12 @@ public void SaveGLB(string path, string fileName) /// /// /// - public byte[] SaveGLBToByteArray(string sceneName) + public byte[] SaveGLBToByteArray(string sceneName, int glbVersion) { _shouldUseInternalBufferForImages = true; using (var stream = new MemoryStream()) { - SaveGLBToStream(stream, sceneName); + SaveGLBToStream(stream, sceneName, glbVersion); return stream.ToArray(); } } @@ -766,7 +766,8 @@ public byte[] SaveGLBToByteArray(string sceneName) /// /// File path for saving the binary file /// The name of the GLTF file - public void SaveGLBToStream(Stream stream, string sceneName) + /// The preferred GLB binary format version (-1, 2 or 3). -1 means auto: It will try 2, but the file exceeds 4 GiB, it will automatically upgrade to 3. + public void SaveGLBToStream(Stream stream, string sceneName, int glbVersion) { exportGltfMarker.Begin(); @@ -816,32 +817,68 @@ public void SaveGLBToStream(Stream stream, string sceneName) _bufferWriter.Flush(); jsonWriter.Flush(); - // align to 4-byte boundary to comply with spec. - AlignToBoundary(jsonStream, (byte)'_'); - AlignToBoundary(binStream, 0x00); - - int glbLength = (int)(GLTFHeaderSize + SectionHeaderSize + - jsonStream.Length + SectionHeaderSize + binStream.Length); + GLTF.GLBHeader glbHeader = new GLTF.GLBHeader + { + Version = (uint)(glbVersion == -1 ? 2 : glbVersion) + }; + // Align chunks to 4-byte or 8-byte boundary to comply with spec. + AlignToBoundary(jsonStream, (byte)' ', glbHeader.GetAlignment()); + AlignToBoundary(binStream, 0x00, glbHeader.GetAlignment()); + long glbLength = jsonStream.Length + binStream.Length + glbHeader.GetFileHeaderSize() + (glbHeader.GetChunkHeaderSize() * 2); + // If automatic, and the file length would be too big for GLB version 2, automatically upgrade to GLB version 3. + if (glbVersion == -1 && glbLength > uint.MaxValue) + { + glbHeader.Version = 3; + AlignToBoundary(jsonStream, (byte)' ', glbHeader.GetAlignment()); + AlignToBoundary(binStream, 0x00, glbHeader.GetAlignment()); + glbLength = jsonStream.Length + binStream.Length + glbHeader.GetFileHeaderSize() + (glbHeader.GetChunkHeaderSize() * 2); + } BinaryWriter writer = new BinaryWriter(stream); - // write header + // Write file header (12 or 16 bytes depending on GLB version). writer.Write(GLTF.GLBHeader.GLTF_MAGIC_NUMBER); - writer.Write(Version); - writer.Write(glbLength); + writer.Write(glbHeader.Version); + if (glbHeader.Version == 2) + { + writer.Write((uint)glbLength); + } + else + { + writer.Write((ulong)glbLength); + } + // Write JSON chunk header (8 or 16 bytes depending on GLB version). gltfWriteJsonStreamMarker.Begin(); - // write JSON chunk header. - writer.Write((int)jsonStream.Length); - writer.Write(MagicJson); + if (glbHeader.Version == 2) + { + writer.Write((uint)jsonStream.Length); + writer.Write((uint)GLTF.GLBChunkFormat.JSON); + } + else + { + writer.Write((uint)GLTF.GLBChunkFormat.JSON); + writer.Write((uint)0); // Plain chunk encoding. + writer.Write((ulong)jsonStream.Length); + } jsonStream.Position = 0; CopyStream(jsonStream, writer); gltfWriteJsonStreamMarker.End(); + // Write binary chunk header (8 or 16 bytes depending on GLB version). gltfWriteBinaryStreamMarker.Begin(); - writer.Write((int)binStream.Length); - writer.Write(MagicBin); + if (glbHeader.Version == 2) + { + writer.Write((uint)binStream.Length); + writer.Write((uint)GLTF.GLBChunkFormat.BIN); + } + else + { + writer.Write((uint)GLTF.GLBChunkFormat.BIN); + writer.Write((uint)0); // Plain chunk encoding. + writer.Write((ulong)binStream.Length); + } binStream.Position = 0; CopyStream(binStream, writer); diff --git a/Runtime/Scripts/GLTFSettings.cs b/Runtime/Scripts/GLTFSettings.cs index 470dfbb0f..0908ddc2e 100644 --- a/Runtime/Scripts/GLTFSettings.cs +++ b/Runtime/Scripts/GLTFSettings.cs @@ -134,6 +134,7 @@ public enum ExportFileFormat } public ExportFileFormat EditorExportFileFormat = ExportFileFormat.Glb; + public bool AllowExporting64BitGLB = false; #endif [Header("Export Visibility")] diff --git a/Runtime/Scripts/Timeline/GLTFRecorder.cs b/Runtime/Scripts/Timeline/GLTFRecorder.cs index c3b04985c..091a5537d 100644 --- a/Runtime/Scripts/Timeline/GLTFRecorder.cs +++ b/Runtime/Scripts/Timeline/GLTFRecorder.cs @@ -396,7 +396,7 @@ public void EndRecording(Stream stream, string sceneName = "scene", GLTFSettings logger = new Logger(logHandler), }); - exporter.SaveGLBToStream(stream, sceneName); + exporter.SaveGLBToStream(stream, sceneName, 2); logHandler.LogAndClear("Export Messages:\n{0}"); }