From 919b7187a05256ef379f0b17faedaee7aa350978 Mon Sep 17 00:00:00 2001 From: Akeit0 Date: Fri, 31 Oct 2025 10:17:01 +0900 Subject: [PATCH 1/6] optimize: reduce utf8-utf16 conversion and json parse --- .../UniGLTF/Runtime/UniGLTF/IO/GltfData.cs | 36 +++++++++++++++++-- .../UniGLTF/IO/Parser/GlbLowLevelParser.cs | 16 +++++---- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/Packages/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs b/Packages/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs index 2841754fd..7b5af2972 100644 --- a/Packages/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs +++ b/Packages/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using UniJSON; using Unity.Collections; namespace UniGLTF @@ -32,7 +33,7 @@ namespace UniGLTF /// JSON chunk ToString /// > This chunk MUST be the very first chunk of Binary glTF asset /// - public string Json { get; } + public string Json => _jsonString ??= _utf8JsonString.ToString(); /// /// GLTF parsed from JSON chunk @@ -72,10 +73,39 @@ namespace UniGLTF /// Dictionary> _UriCache = new Dictionary>(); + /// + /// json string in utf8 + /// + Utf8String _utf8JsonString; + + /// + /// json string cache + /// + string _jsonString; + public GltfData(string targetPath, string json, glTF gltf, IReadOnlyList chunks, IStorage storage, MigrationFlags migrationFlags) { TargetPath = targetPath; - Json = json; + _jsonString = json; + GLTF = gltf; + Chunks = chunks; + _storage = storage; + MigrationFlags = migrationFlags; + + // init + if (Chunks != null) + { + if (Chunks.Count >= 2) + { + Bin = NativeArrayManager.CreateNativeArray(Chunks[1].Bytes); + } + } + } + + internal GltfData(string targetPath, Utf8String jsonString, glTF gltf, IReadOnlyList chunks, IStorage storage, MigrationFlags migrationFlags) + { + TargetPath = targetPath; + _utf8JsonString = jsonString; GLTF = gltf; Chunks = chunks; _storage = storage; @@ -441,4 +471,4 @@ namespace UniGLTF return false; } } -} +} \ No newline at end of file diff --git a/Packages/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs b/Packages/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs index 2207bc6cd..4aa2739d3 100644 --- a/Packages/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs +++ b/Packages/UniGLTF/Runtime/UniGLTF/IO/Parser/GlbLowLevelParser.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Text; using System.Text.RegularExpressions; using UniJSON; @@ -33,7 +32,7 @@ namespace UniGLTF var jsonBytes = chunks[0].Bytes; return ParseGltf( _path, - Encoding.UTF8.GetString(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count), + new Utf8String(new ArraySegment(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count)), chunks, default, new MigrationFlags() @@ -73,14 +72,20 @@ namespace UniGLTF public static GltfData ParseGltf(string path, string json, IReadOnlyList chunks, IStorage storage, MigrationFlags migrationFlags) { - var GLTF = GltfDeserializer.Deserialize(json.ParseAsJson()); + return ParseGltf(path, Utf8String.From(json), chunks, storage, migrationFlags); + } + + internal static GltfData ParseGltf(string path, Utf8String json, IReadOnlyList chunks, IStorage storage, MigrationFlags migrationFlags) + { + var parsedJson = json.ParseAsJson(); + var GLTF = GltfDeserializer.Deserialize(parsedJson); if (GLTF.asset.version != "2.0") { throw new UniGLTFException("unknown gltf version {0}", GLTF.asset.version); } // Version Compatibility - RestoreOlderVersionValues(json, GLTF); + RestoreOlderVersionValues(parsedJson, GLTF); FixMeshNameUnique(GLTF); FixBlendShapeNameUnique(GLTF); @@ -298,9 +303,8 @@ namespace UniGLTF } } - private static void RestoreOlderVersionValues(string Json, glTF GLTF) + private static void RestoreOlderVersionValues(JsonNode parsed, glTF GLTF) { - var parsed = UniJSON.JsonParser.Parse(Json); for (int i = 0; i < GLTF.images.Count; ++i) { if (string.IsNullOrEmpty(GLTF.images[i].name)) From 5bf3e203627c73559fc64b67125998420db13e50 Mon Sep 17 00:00:00 2001 From: Akeit0 Date: Fri, 31 Oct 2025 10:34:27 +0900 Subject: [PATCH 2/6] optimize: reduce allocation for parsing floating point numbers --- .../Runtime/UniJSON/Utf8String/Utf8String.cs | 4 +- .../Utf8String/Utf8StringExtensions.cs | 41 ++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Packages/UniGLTF/Runtime/UniJSON/Utf8String/Utf8String.cs b/Packages/UniGLTF/Runtime/UniJSON/Utf8String/Utf8String.cs index 020f127f8..734132be4 100644 --- a/Packages/UniGLTF/Runtime/UniJSON/Utf8String/Utf8String.cs +++ b/Packages/UniGLTF/Runtime/UniJSON/Utf8String/Utf8String.cs @@ -110,6 +110,8 @@ namespace UniJSON return new Utf8String(bytes); } + public ReadOnlySpan AsSpan() => Bytes.AsSpan(); + public override string ToString() { if (ByteLength == 0) return ""; @@ -324,4 +326,4 @@ namespace UniJSON } } } -} +} \ No newline at end of file diff --git a/Packages/UniGLTF/Runtime/UniJSON/Utf8String/Utf8StringExtensions.cs b/Packages/UniGLTF/Runtime/UniJSON/Utf8String/Utf8StringExtensions.cs index e0df03db3..8222a258a 100644 --- a/Packages/UniGLTF/Runtime/UniJSON/Utf8String/Utf8StringExtensions.cs +++ b/Packages/UniGLTF/Runtime/UniJSON/Utf8String/Utf8StringExtensions.cs @@ -1,5 +1,7 @@ using System; +using System.Buffers; using System.Collections.Generic; +using System.Globalization; using System.IO; @@ -320,11 +322,46 @@ namespace UniJSON public static float ToSingle(this Utf8String src) { - return Single.Parse(src.ToAscii(), System.Globalization.CultureInfo.InvariantCulture); + char[] arrayToReturn = null; + try + { + var srcBytes = src.AsSpan(); + Span chars = srcBytes.Length < 64 + ? stackalloc char[srcBytes.Length] + : arrayToReturn = ArrayPool.Shared.Rent(srcBytes.Length); + var count = System.Text.Encoding.ASCII.GetChars(srcBytes, chars); + return Single.Parse(chars[..count], NumberStyles.Float | NumberStyles.AllowThousands, + System.Globalization.CultureInfo.InvariantCulture); + } + finally + { + if (arrayToReturn != null) + { + ArrayPool.Shared.Return(arrayToReturn); + } + } } + public static double ToDouble(this Utf8String src) { - return Double.Parse(src.ToAscii(), System.Globalization.CultureInfo.InvariantCulture); + char[] arrayToReturn = null; + try + { + var srcBytes = src.AsSpan(); + Span chars = srcBytes.Length < 64 + ? stackalloc char[srcBytes.Length] + : arrayToReturn = ArrayPool.Shared.Rent(srcBytes.Length); + var count = System.Text.Encoding.ASCII.GetChars(srcBytes, chars); + return Double.Parse(chars[..count], NumberStyles.Float | NumberStyles.AllowThousands, + System.Globalization.CultureInfo.InvariantCulture); + } + finally + { + if (arrayToReturn != null) + { + ArrayPool.Shared.Return(arrayToReturn); + } + } } public static Utf8String GetLine(this Utf8String src) From e2a88761ebfabd2e6be24b3bcbed4ea116f1ef6a Mon Sep 17 00:00:00 2001 From: Akeit0 Date: Fri, 31 Oct 2025 10:40:20 +0900 Subject: [PATCH 3/6] optimize: Unescape fast path --- .../Runtime/UniJSON/Json/JsonString.cs | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/Packages/UniGLTF/Runtime/UniJSON/Json/JsonString.cs b/Packages/UniGLTF/Runtime/UniJSON/Json/JsonString.cs index ed145f272..712593d78 100644 --- a/Packages/UniGLTF/Runtime/UniJSON/Json/JsonString.cs +++ b/Packages/UniGLTF/Runtime/UniJSON/Json/JsonString.cs @@ -395,6 +395,28 @@ namespace UniJSON return writeCount; } + private static Utf8String Unescape(Utf8String s) + { + var span = s.AsSpan(); + var escapeIndex = span.IndexOf((byte)'\\'); + + // escape not found + if (escapeIndex == -1) + { + return s; + } + + var sb = new BytesStore(s.ByteLength); + foreach (var b in span[..escapeIndex]) + { + sb.Write(b); + } + + Unescape(s.Subbytes(escapeIndex), sb); + return new Utf8String(sb.Bytes); + } + + public static string Unescape(string src) { var sb = new StringBuilder(); @@ -430,18 +452,9 @@ namespace UniJSON public static Utf8String Unquote(Utf8String src) { - var count = Unquote(src, null); - if (count == src.ByteLength - 2) - { - return src.Subbytes(1, src.ByteLength - 2); - } - else - { - var sb = new BytesStore(count); - Unquote(src, sb); - return new Utf8String(sb.Bytes); - } + return Unescape(src.Subbytes(1, src.ByteLength - 2)); } + #endregion } -} +} \ No newline at end of file From d80a8ba0e26695e6becc1141a31e2ab44e644776 Mon Sep 17 00:00:00 2001 From: Akeit0 Date: Fri, 31 Oct 2025 10:41:53 +0900 Subject: [PATCH 4/6] change unquoting order --- Packages/UniGLTF/Runtime/UniJSON/Json/JsonValue.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Packages/UniGLTF/Runtime/UniJSON/Json/JsonValue.cs b/Packages/UniGLTF/Runtime/UniJSON/Json/JsonValue.cs index 450308540..1e0d6545f 100644 --- a/Packages/UniGLTF/Runtime/UniJSON/Json/JsonValue.cs +++ b/Packages/UniGLTF/Runtime/UniJSON/Json/JsonValue.cs @@ -101,7 +101,7 @@ namespace UniJSON public UInt64 GetUInt64() { return Segment.ToUInt64(); } public Single GetSingle() { return Segment.ToSingle(); } public Double GetDouble() { return Segment.ToDouble(); } - public String GetString() { return JsonString.Unquote(Segment.ToString()); } + public String GetString() { return JsonString.Unquote(Segment).ToString(); } public Utf8String GetUtf8String() { return JsonString.Unquote(Segment); } } -} +} \ No newline at end of file From 7a7ba6b9ad4fb010332e46b29e6b403e65165a97 Mon Sep 17 00:00:00 2001 From: Christian Petry Date: Wed, 12 Nov 2025 08:13:10 +0100 Subject: [PATCH 5/6] Fixes #2748 - Adjusted URP emissiveFactor analog to Built-in material --- .../URP/Export/Materials/UrpLitMaterialExporter.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Packages/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Export/Materials/UrpLitMaterialExporter.cs b/Packages/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Export/Materials/UrpLitMaterialExporter.cs index e0bf6a4f2..6763628e6 100644 --- a/Packages/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Export/Materials/UrpLitMaterialExporter.cs +++ b/Packages/UniGLTF/Runtime/UniGLTF/IO/MaterialIO/URP/Export/Materials/UrpLitMaterialExporter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UnityEngine; using UnityEngine.Rendering; @@ -174,7 +175,16 @@ namespace UniGLTF { if (!context.IsEmissionEnabled) return; - dst.emissiveFactor = context.EmissionColorLinear.ToFloat3(ColorSpace.Linear, ColorSpace.Linear); + var emissiveFactor = context.EmissionColorLinear.ToFloat3(ColorSpace.Linear, ColorSpace.Linear); + // Unity uses HDR color for emission factor. Normalize it if any component is greater than 1. + // If not normalized, glTF validator throws an error "VALUE_NOT_IN_RANGE" + var maxComponent = emissiveFactor.Max(); + if (maxComponent > 1) + { + emissiveFactor = emissiveFactor.Select(x => x / maxComponent).ToArray(); + glTF_KHR_materials_emissive_strength.Serialize(ref dst.extensions, maxComponent); + } + dst.emissiveFactor = emissiveFactor; if (context.EmissionTexture != null) { var index = textureExporter.RegisterExportingAsSRgb(context.EmissionTexture, true); From 7e482e1bfe98d89ce6850810f58bf01af2c618c2 Mon Sep 17 00:00:00 2001 From: amamagi <36906576+amamagi@users.noreply.github.com> Date: Tue, 25 Nov 2025 17:12:54 +0900 Subject: [PATCH 6/6] fix: guess mimeType when uri is DataURI and mimeType is empty --- .../UniGLTF/Runtime/UniGLTF/IO/GltfData.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Packages/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs b/Packages/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs index 7b5af2972..7126eca66 100644 --- a/Packages/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs +++ b/Packages/UniGLTF/Runtime/UniGLTF/IO/GltfData.cs @@ -397,6 +397,24 @@ namespace UniGLTF { return null; } + + // for Data URI + if (uri.StartsWith("data:", StringComparison.Ordinal)) + { + var headerEnd = uri.IndexOf(','); + if (headerEnd < 0) + { + return null; + } + + const int dataPrefixLength = 5; // "data:".Length + var header = uri[dataPrefixLength..headerEnd]; + var semicolonPos = header.IndexOf(';'); + var mime = semicolonPos >= 0 ? header[..semicolonPos] : header; + + return mime is "image/png" or "image/jpeg" ? mime : null; + } + var ext = System.IO.Path.GetExtension(uri).ToLowerInvariant(); switch (ext) {