Texture読み込みをなるべくNativeArrayによせる

This commit is contained in:
momoma-null 2026-06-19 18:48:18 +09:00 committed by hadashiA
parent dcf20ab3c6
commit f0a79d1a34
6 changed files with 34 additions and 53 deletions

View File

@ -1,4 +1,5 @@
using UnityEngine;
using Unity.Collections;
using UnityEngine;
namespace UniGLTF
{
@ -8,9 +9,11 @@ namespace UniGLTF
public sealed class DeserializingTextureInfo
{
/// <summary>
/// Texture のバイト列
/// Texture のバイト列。
/// GltfData が保持する NativeArray をコピーせずそのまま参照するため、Dispose してはならない。
/// 未設定の場合は IsCreated == false となる。
/// </summary>
public byte[] ImageData { get; }
public NativeArray<byte> ImageData { get; }
/// <summary>
/// Texture の mimeType
@ -44,7 +47,7 @@ namespace UniGLTF
public TextureImportTypes ImportTypes { get; }
public DeserializingTextureInfo(byte[] imageData, string dataMimeType, ColorSpace colorSpace, bool useMipmap, FilterMode filterMode, TextureWrapMode wrapModeU, TextureWrapMode wrapModeV)
public DeserializingTextureInfo(NativeArray<byte> imageData, string dataMimeType, ColorSpace colorSpace, bool useMipmap, FilterMode filterMode, TextureWrapMode wrapModeU, TextureWrapMode wrapModeV)
{
ImageData = imageData;
DataMimeType = dataMimeType;
@ -55,7 +58,7 @@ namespace UniGLTF
WrapModeV = wrapModeV;
}
public DeserializingTextureInfo(byte[] imageData, string dataMimeType, ColorSpace colorSpace, SamplerParam samplerParam, TextureImportTypes importTypes)
public DeserializingTextureInfo(NativeArray<byte> imageData, string dataMimeType, ColorSpace colorSpace, SamplerParam samplerParam, TextureImportTypes importTypes)
{
ImageData = imageData;
DataMimeType = dataMimeType;

View File

@ -23,11 +23,7 @@ namespace UniGLTF
TextureImportTypes.sRGB,
default,
default,
() =>
{
var imageBytes = data.GetBytesFromImage(imageIndex);
return Task.FromResult<(byte[], string)?>((ToArray(imageBytes?.binary ?? default), imageBytes?.mimeType));
},
() => Task.FromResult(GetImageBytesFromImageIndex(data, imageIndex)),
default, default, default, default, default);
return (texDesc.SubAssetKey, texDesc);
}
@ -214,19 +210,10 @@ namespace UniGLTF
return (offset, scale);
}
private static (byte[] binary, string mimeType)? GetImageBytesFromImageIndex(GltfData data, int imageIndex)
private static (NativeArray<byte> binary, string mimeType)? GetImageBytesFromImageIndex(GltfData data, int imageIndex)
{
if (imageIndex >= 0 && imageIndex < data.GLTF.images.Count)
{
var imageBytes = data.GetBytesFromImage(imageIndex);
if (imageBytes.HasValue)
{
return (ToArray(imageBytes.Value.binary), imageBytes.Value.mimeType);
}
}
return default;
// NOTE: GltfData が保持する NativeArray をコピーせずそのまま返す。
return data.GetBytesFromImage(imageIndex);
}
private static int? GetImageIndexFromTextureIndex(GltfData data, int textureIndex)
@ -272,25 +259,5 @@ namespace UniGLTF
}
return true;
}
private static byte[] ToArray(NativeArray<byte> bytes)
{
// if (bytes.Array == null)
// {
// return new byte[] { };
// }
// else if (bytes.Offset == 0 && bytes.Count == bytes.Array.Length)
// {
// return bytes.Array;
// }
// else
// {
// var result = new byte[bytes.Count];
// Buffer.BlockCopy(bytes.Array, bytes.Offset, result, 0, result.Length);
// return result;
// }
return bytes.ToArray();
}
}
}

View File

@ -15,15 +15,16 @@ namespace UniGLTF
#pragma warning restore 1998
{
#if USE_COM_UNITY_CLOUD_KTX
if (textureInfo.ImageData == null) return null;
if (!textureInfo.ImageData.IsCreated) return null;
// NOTE: IAwaitCaller を無視するので、同期読み込みを期待する環境で同期読み込みができない
try
{
var ktxTexture = new KtxTexture();
using var nativeBytes = new NativeArray<byte>(textureInfo.ImageData, Allocator.Persistent);
// NOTE: GltfData が保持する NativeArray をそのまま渡す。
// KtxUnity は Open() 内で同期的に読み取るだけで所有権を取らないため、コピー不要。
var result = await ktxTexture.LoadFromBytes(
nativeBytes,
textureInfo.ImageData,
linear: textureInfo.ColorSpace == ColorSpace.Linear,
mipChain: textureInfo.UseMipmap
);

View File

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Unity.Collections;
using UnityEngine;
namespace UniGLTF
@ -11,9 +12,12 @@ namespace UniGLTF
/// Texture2D.LoadImage
/// extact:
/// File.WriteAllBytes
///
/// NOTE: binary は GltfData が保持する NativeArray をそのまま参照する。
/// コピーを避けるため、呼び出し側で Dispose してはならない。
/// </summary>
/// <returns></returns>
public delegate Task<(byte[] binary, string mimeType)?> GetTextureBytesAsync();
public delegate Task<(NativeArray<byte> binary, string mimeType)?> GetTextureBytesAsync();
/// <summary>
/// 入力 glTF ファイルを Import した結果生成される、UnityEngine.Texture のアセット 1 つを確定させる Import 情報。

View File

@ -84,7 +84,7 @@ namespace UniGLTF
// https://docs.unity3d.com/2018.4/Documentation/Manual/StandardShaderMaterialParameterNormalMap.html
var data0 = await texDesc.Index0();
var rawTexture = await TextureDeserializer.LoadTextureAsync(
new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
new DeserializingTextureInfo(data0?.binary ?? default, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
awaitCaller);
rawTexture.name = subAssetKey.Name;
_textureCache.Add(subAssetKey, rawTexture);
@ -100,14 +100,14 @@ namespace UniGLTF
{
var data0 = await texDesc.Index0();
metallicRoughnessTexture = await TextureDeserializer.LoadTextureAsync(
new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
new DeserializingTextureInfo(data0?.binary ?? default, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
awaitCaller);
}
if (texDesc.Index1 != null)
{
var data1 = await texDesc.Index1();
occlusionTexture = await TextureDeserializer.LoadTextureAsync(
new DeserializingTextureInfo(data1?.binary, data1?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
new DeserializingTextureInfo(data1?.binary ?? default, data1?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
awaitCaller);
}
@ -127,7 +127,7 @@ namespace UniGLTF
{
var data0 = await texDesc.Index0();
var rawTexture = await TextureDeserializer.LoadTextureAsync(
new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.sRGB, texDesc.Sampler, texDesc.TextureType),
new DeserializingTextureInfo(data0?.binary ?? default, data0?.mimeType, ColorSpace.sRGB, texDesc.Sampler, texDesc.TextureType),
awaitCaller);
rawTexture.name = subAssetKey.Name;
_textureCache.Add(subAssetKey, rawTexture);
@ -137,7 +137,7 @@ namespace UniGLTF
{
var data0 = await texDesc.Index0();
var rawTexture = await TextureDeserializer.LoadTextureAsync(
new DeserializingTextureInfo(data0?.binary, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
new DeserializingTextureInfo(data0?.binary ?? default, data0?.mimeType, ColorSpace.Linear, texDesc.Sampler, texDesc.TextureType),
awaitCaller);
rawTexture.name = subAssetKey.Name;
_textureCache.Add(subAssetKey, rawTexture);

View File

@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
using Unity.Collections;
using UnityEngine;
namespace UniGLTF
@ -29,12 +30,17 @@ namespace UniGLTF
public async Task<Texture2D> LoadTextureAsync(DeserializingTextureInfo textureInfo, IAwaitCaller awaitCaller)
{
if (textureInfo.ImageData == null) return null;
if (!textureInfo.ImageData.IsCreated) return null;
try
{
var texture = new Texture2D(2, 2, TextureFormat.ARGB32, textureInfo.UseMipmap, textureInfo.ColorSpace == ColorSpace.Linear);
texture.LoadImage(textureInfo.ImageData, ImportedTexturesAccessibility.ToMarkNonReadable());
#if UNITY_6000_0_OR_NEWER
// Unity 6000.0.42f1 以降は LoadImage が ReadOnlySpan を受け取れるため、NativeArray からのコピーを避ける。
texture.LoadImage(textureInfo.ImageData.AsReadOnlySpan(), ImportedTexturesAccessibility.ToMarkNonReadable());
#else
texture.LoadImage(textureInfo.ImageData.ToArray(), ImportedTexturesAccessibility.ToMarkNonReadable());
#endif
await awaitCaller.NextFrame();
texture.wrapModeU = textureInfo.WrapModeU;