Merge pull request #986 from Santarh/texDeserialize

Extension implementation can inject texture loading strategy to ImporterContext
This commit is contained in:
ousttrue 2021-05-27 23:50:19 +09:00 committed by GitHub
commit 0c3d7b2ab8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 128 additions and 187 deletions

View File

@ -2,7 +2,7 @@
using UnityEditor;
using UnityEngine;
using VRMShaders;
using ColorSpace = UniGLTF.ColorSpace;
using ColorSpace = VRMShaders.ColorSpace;
namespace MeshUtility
{

View File

@ -1,5 +1,6 @@
using System;
using UnityEngine;
using ColorSpace = VRMShaders.ColorSpace;
namespace UniGLTF
{
@ -10,13 +11,13 @@ namespace UniGLTF
var dst = src.ConvertColorSpace(srcColorSpace, dstColorSpace);
return new float[] {dst.r, dst.g, dst.b, dst.a};
}
public static float[] ToFloat3(this Color src, ColorSpace srcColorSpace, ColorSpace dstColorSpace)
{
var dst = src.ConvertColorSpace(srcColorSpace, dstColorSpace);
return new float[] {dst.r, dst.g, dst.b};
}
public static Color ToColor4(this float[] src, ColorSpace srcColorSpace, ColorSpace dstColorSpace)
{
if (src == null || src.Length < 4)
@ -27,7 +28,7 @@ namespace UniGLTF
return new Color(src[0], src[1], src[2], src[3]).ConvertColorSpace(srcColorSpace, dstColorSpace);
}
public static Color ToColor3(this float[] src, ColorSpace srcColorSpace, ColorSpace dstColorSpace)
{
if (src == null || src.Length < 3)
@ -64,4 +65,4 @@ namespace UniGLTF
}
}
}
}
}

View File

@ -37,14 +37,19 @@ namespace UniGLTF
public TextureFactory TextureFactory { get; }
public MaterialFactory MaterialFactory { get; }
public ImporterContext(GltfParser parser, IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> externalObjectMap = null)
public ImporterContext(
GltfParser parser,
IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> externalObjectMap = null,
ITextureDeserializer textureDeserializer = null)
{
Parser = parser;
TextureDescriptorGenerator = new GltfTextureDescriptorGenerator(Parser);
MaterialDescriptorGenerator = new GltfMaterialDescriptorGenerator();
externalObjectMap = externalObjectMap ?? new Dictionary<SubAssetKey, UnityEngine.Object>();
TextureFactory = new TextureFactory(externalObjectMap
textureDeserializer = textureDeserializer ?? new UnityTextureDeserializer();
TextureFactory = new TextureFactory(textureDeserializer, externalObjectMap
.Where(x => x.Value is Texture)
.ToDictionary(x => x.Key, x => (Texture) x.Value));
MaterialFactory = new MaterialFactory(externalObjectMap

View File

@ -1,5 +1,6 @@
using UnityEngine;
using VRMShaders;
using ColorSpace = VRMShaders.ColorSpace;
namespace UniGLTF
{

View File

@ -1,6 +1,6 @@
using UnityEngine;
using VRMShaders;
using ColorSpace = VRMShaders.ColorSpace;
namespace UniGLTF
{

View File

@ -2,7 +2,7 @@
using UniGLTF.UniUnlit;
using UnityEngine;
using VRMShaders;
using ColorSpace = VRMShaders.ColorSpace;
namespace UniGLTF
{

View File

@ -1,6 +1,7 @@
using System;
using UnityEngine;
using VRMShaders;
using ColorSpace = VRMShaders.ColorSpace;
namespace UniGLTF
{

View File

@ -1,68 +0,0 @@
Shader "UniGLTF/NormalMapEncoder"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
fixed4 frag(v2f i) : SV_Target
{
half4 col = tex2D(_MainTex, i.uv);
half4 packedNormal;
packedNormal.x = col.x;
packedNormal.y = col.y;
packedNormal.z = col.z;
packedNormal.w = 1.0;
// normalize as normal vector
float3 normal;
normal.xy = packedNormal.xy * 2 - 1;
if (dot(normal.xy, normal.xy) > 1)
{
normal.xy = normalize(normal.xy);
}
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
packedNormal.xyz = normal.xyz * 0.5 + 0.5;
return packedNormal;
}
ENDCG
}
}
}

View File

@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: 3e39586253f31b34f87fa7e133449b1e
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,8 +3,8 @@ using System.Linq;
using UniGLTF;
using UniJSON;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
using VRMShaders;
using ColorSpace = VRMShaders.ColorSpace;
namespace VRM
{

View File

@ -20,8 +20,11 @@ namespace VRM
public VRM.glTF_VRM_extensions VRM { get; private set; }
public VRMImporterContext(GltfParser parser, IReadOnlyDictionary<SubAssetKey, Object> externalObjectMap = null)
: base(parser, externalObjectMap)
public VRMImporterContext(
GltfParser parser,
IReadOnlyDictionary<SubAssetKey, Object> externalObjectMap = null,
ITextureDeserializer textureDeserializer = null)
: base(parser, externalObjectMap, textureDeserializer)
{
// parse VRM part
if (glTF_VRM_extensions.TryDeserialize(GLTF.extensions, out glTF_VRM_extensions vrm))

View File

@ -5,7 +5,7 @@ using UniGLTF;
using UniGLTF.ShaderPropExporter;
using UnityEngine;
using VRMShaders;
using ColorSpace = UniGLTF.ColorSpace;
using ColorSpace = VRMShaders.ColorSpace;
namespace VRM
{

View File

@ -4,7 +4,7 @@ using UniGLTF;
using UniGLTF.Extensions.VRMC_materials_mtoon;
using UnityEngine;
using VRMShaders;
using ColorSpace = UniGLTF.ColorSpace;
using ColorSpace = VRMShaders.ColorSpace;
using OutlineWidthMode = MToon.OutlineWidthMode;
using RenderMode = MToon.RenderMode;

View File

@ -4,7 +4,7 @@ using UniGLTF;
using UniGLTF.Extensions.VRMC_materials_mtoon;
using UnityEngine;
using VRMShaders;
using ColorSpace = UniGLTF.ColorSpace;
using ColorSpace = VRMShaders.ColorSpace;
using OutlineWidthMode = UniGLTF.Extensions.VRMC_materials_mtoon.OutlineWidthMode;
namespace UniVRM10

View File

@ -21,8 +21,11 @@ namespace UniVRM10
IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> m_externalMap;
public Vrm10Importer(UniGLTF.GltfParser parser, IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> externalObjectMap = null)
: base(parser, externalObjectMap)
public Vrm10Importer(
UniGLTF.GltfParser parser,
IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> externalObjectMap = null,
ITextureDeserializer textureDeserializer = null)
: base(parser, externalObjectMap, textureDeserializer)
{
TextureDescriptorGenerator = new Vrm10TextureDescriptorGenerator(parser);
MaterialDescriptorGenerator = new Vrm10MaterialDescriptorGenerator();

View File

@ -5,7 +5,7 @@ using UniGLTF;
using UniGLTF.Extensions.VRMC_materials_mtoon;
using UniJSON;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
using ColorSpace = VRMShaders.ColorSpace;
using RenderMode = MToon.RenderMode;
namespace UniVRM10

View File

@ -1,10 +1,8 @@
using System;
using System.IO;
using System.Reflection;
using UniGLTF;
using UnityEditor;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{

View File

@ -1,8 +1,8 @@
namespace UniGLTF
namespace VRMShaders
{
public enum ColorSpace
{
sRGB,
Linear,
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Threading.Tasks;
using UnityEngine;
namespace VRMShaders
{
/// <summary>
/// 単純に Texture2D アセットを生成する機能
/// </summary>
public interface ITextureDeserializer
{
/// <summary>
/// imageData をもとに Texture2D を生成する
/// </summary>
/// <param name="imageData">データ</param>
/// <param name="useMipmap">Texture2D の mipmap が生成されるべきか否か</param>
/// <param name="colorSpace">Texture2D の色空間</param>
/// <returns></returns>
Task<Texture2D> LoadTextureAsync(byte[] imageData, bool useMipmap, ColorSpace colorSpace);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 47b889c85e814e7eae6f5b7f760c7ef3
timeCreated: 1622107590

View File

@ -13,7 +13,7 @@ namespace VRMShaders
/// <summary>
/// Export する Texture2D のリスト。これが gltf.textures になる
/// </summary>
IReadOnlyList<(Texture2D, UniGLTF.ColorSpace)> Exported { get; }
IReadOnlyList<(Texture2D, ColorSpace)> Exported { get; }
/// <summary>
/// 指定の Texture を、 sRGB 色空間の値を持つ Texture に出力するように指示する。

View File

@ -1,6 +1,6 @@
using UnityEngine;
namespace UniGLTF
namespace VRMShaders
{
/// <summary>
/// Texture2D を入力として byte[] を得る機能

View File

@ -1,6 +1,4 @@
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{
@ -19,28 +17,7 @@ namespace VRMShaders
}
}
private static Material m_encoder;
private static Material Encoder
{
get
{
if (m_encoder == null)
{
m_encoder = new Material(Shader.Find("UniGLTF/NormalMapEncoder"));
}
return m_encoder;
}
}
// GLTF data to Unity texture
// ConvertToNormalValueFromRawColorWhenCompressionIsRequired
public static Texture2D Import(Texture2D texture)
{
return TextureConverter.CopyTexture(texture, ColorSpace.Linear, false, Encoder);
}
// Unity texture to GLTF data
// ConvertToRawColorWhenNormalValueIsCompressed
public static Texture2D Export(Texture texture)
{
return TextureConverter.CopyTexture(texture, ColorSpace.Linear, false, Decoder);

View File

@ -1,8 +1,6 @@
using System;
using System.Linq;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{

View File

@ -2,7 +2,7 @@
using UnityEngine;
using VRMShaders;
namespace UniGLTF
namespace VRMShaders
{
public sealed class RuntimeTextureSerializer : ITextureSerializer
{

View File

@ -1,8 +1,6 @@
using System;
using System.Linq;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{

View File

@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using UniGLTF;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{

View File

@ -3,40 +3,40 @@ using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.Threading.Tasks;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{
public class TextureFactory : IDisposable
{
private readonly Dictionary<SubAssetKey, Texture> m_temporaryTextures = new Dictionary<SubAssetKey, Texture>();
private readonly Dictionary<SubAssetKey, Texture> m_textureCache = new Dictionary<SubAssetKey, Texture>();
private readonly IReadOnlyDictionary<SubAssetKey, Texture> m_externalMap;
private readonly ITextureDeserializer _textureDeserializer;
private readonly IReadOnlyDictionary<SubAssetKey, Texture> _externalMap;
private readonly Dictionary<SubAssetKey, Texture> _temporaryTextures = new Dictionary<SubAssetKey, Texture>();
private readonly Dictionary<SubAssetKey, Texture> _textureCache = new Dictionary<SubAssetKey, Texture>();
/// <summary>
/// Importer が動的に生成した Texture
/// </summary>
public IReadOnlyDictionary<SubAssetKey, Texture> ConvertedTextures => m_textureCache;
public IReadOnlyDictionary<SubAssetKey, Texture> ConvertedTextures => _textureCache;
/// <summary>
///
/// 外部から渡された、すでに存在する Texture (ex. Extracted Editor Asset)
/// </summary>
public IReadOnlyDictionary<SubAssetKey, Texture> ExternalTextures => m_externalMap;
public IReadOnlyDictionary<SubAssetKey, Texture> ExternalTextures => _externalMap;
public TextureFactory(IReadOnlyDictionary<SubAssetKey, Texture> externalTextures)
public TextureFactory(ITextureDeserializer textureDeserializer, IReadOnlyDictionary<SubAssetKey, Texture> externalTextures)
{
m_externalMap = externalTextures;
_textureDeserializer = textureDeserializer;
_externalMap = externalTextures;
}
public void Dispose()
{
foreach (var kv in m_temporaryTextures)
foreach (var kv in _temporaryTextures)
{
DestroyResource(kv.Value);
}
m_temporaryTextures.Clear();
m_textureCache.Clear();
_temporaryTextures.Clear();
_textureCache.Clear();
}
/// <summary>
@ -46,7 +46,7 @@ namespace VRMShaders
public void TransferOwnership(Func<UnityEngine.Object, bool> take)
{
var transferredAssets = new HashSet<SubAssetKey>();
foreach (var x in m_textureCache)
foreach (var x in _textureCache)
{
if (take(x.Value))
{
@ -56,41 +56,24 @@ namespace VRMShaders
foreach (var key in transferredAssets)
{
m_textureCache.Remove(key);
_textureCache.Remove(key);
}
}
async Task<Texture2D> LoadTextureAsync(GetTextureBytesAsync getTextureBytesAsync, bool useMipmap, ColorSpace colorSpace)
{
var imageBytes = await getTextureBytesAsync();
var texture = new Texture2D(2, 2, TextureFormat.ARGB32, useMipmap, colorSpace == ColorSpace.Linear);
if (imageBytes != null)
{
texture.LoadImage(imageBytes);
}
return texture;
}
/// <summary>
/// テクスチャーをロード、必要であれば変換して返す
/// 同じものはキャッシュを返す
/// テクスチャ生成情報を基に、テクスチャ生成を行う。
/// SubAssetKey が同じ場合はキャッシュを返す。
/// </summary>
/// <param name="texture_type">変換の有無を判断する: METALLIC_GLOSS_PROP</param>
/// <param name="roughnessFactor">METALLIC_GLOSS_PROPの追加パラメーター</param>
/// <param name="indices">gltf の texture index</param>
/// <returns></returns>
public async Task<Texture> GetTextureAsync(TextureDescriptor texDesc)
{
var subAssetKey = texDesc.SubAssetKey;
if (m_externalMap != null && m_externalMap.TryGetValue(subAssetKey, out var externalTexture))
if (_externalMap != null && _externalMap.TryGetValue(subAssetKey, out var externalTexture))
{
return externalTexture;
}
if (m_textureCache.TryGetValue(subAssetKey, out var cachedTexture))
if (_textureCache.TryGetValue(subAssetKey, out var cachedTexture))
{
return cachedTexture;
}
@ -99,14 +82,16 @@ namespace VRMShaders
{
case TextureImportTypes.NormalMap:
{
// Runtime/SubAsset 用に変換する
var rawTexture = await LoadTextureAsync(texDesc.Index0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear);
var convertedTexture = NormalConverter.Import(rawTexture);
convertedTexture.name = subAssetKey.Name;
convertedTexture.SetSampler(texDesc.Sampler);
m_textureCache.Add(subAssetKey, convertedTexture);
DestroyResource(rawTexture);
return convertedTexture;
// no conversion. Unity's normal map is same with glTF's.
//
// > contrary to Unitys usual convention of using Y as “up”
// https://docs.unity3d.com/2018.4/Documentation/Manual/StandardShaderMaterialParameterNormalMap.html
var data0 = await texDesc.Index0();
var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear);
rawTexture.name = subAssetKey.Name;
rawTexture.SetSampler(texDesc.Sampler);
_textureCache.Add(subAssetKey, rawTexture);
return rawTexture;
}
case TextureImportTypes.StandardMap:
@ -116,18 +101,20 @@ namespace VRMShaders
if (texDesc.Index0 != null)
{
metallicRoughnessTexture = await LoadTextureAsync(texDesc.Index0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear);
var data0 = await texDesc.Index0();
metallicRoughnessTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear);
}
if (texDesc.Index1 != null)
{
occlusionTexture = await LoadTextureAsync(texDesc.Index1, texDesc.Sampler.EnableMipMap, ColorSpace.Linear);
var data1 = await texDesc.Index1();
occlusionTexture = await _textureDeserializer.LoadTextureAsync(data1, texDesc.Sampler.EnableMipMap, ColorSpace.Linear);
}
var combinedTexture = OcclusionMetallicRoughnessConverter.Import(metallicRoughnessTexture,
texDesc.MetallicFactor, texDesc.RoughnessFactor, occlusionTexture);
combinedTexture.name = subAssetKey.Name;
combinedTexture.SetSampler(texDesc.Sampler);
m_textureCache.Add(subAssetKey, combinedTexture);
_textureCache.Add(subAssetKey, combinedTexture);
DestroyResource(metallicRoughnessTexture);
DestroyResource(occlusionTexture);
return combinedTexture;
@ -135,18 +122,20 @@ namespace VRMShaders
case TextureImportTypes.sRGB:
{
var rawTexture = await LoadTextureAsync(texDesc.Index0, texDesc.Sampler.EnableMipMap, ColorSpace.sRGB);
var data0 = await texDesc.Index0();
var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.sRGB);
rawTexture.name = subAssetKey.Name;
rawTexture.SetSampler(texDesc.Sampler);
m_textureCache.Add(subAssetKey, rawTexture);
_textureCache.Add(subAssetKey, rawTexture);
return rawTexture;
}
case TextureImportTypes.Linear:
{
var rawTexture = await LoadTextureAsync(texDesc.Index0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear);
var data0 = await texDesc.Index0();
var rawTexture = await _textureDeserializer.LoadTextureAsync(data0, texDesc.Sampler.EnableMipMap, ColorSpace.Linear);
rawTexture.name = subAssetKey.Name;
rawTexture.SetSampler(texDesc.Sampler);
m_textureCache.Add(subAssetKey, rawTexture);
_textureCache.Add(subAssetKey, rawTexture);
return rawTexture;
}
default:

View File

@ -1,6 +1,5 @@
using System;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{

View File

@ -0,0 +1,23 @@
using System;
using System.Threading.Tasks;
using UnityEngine;
namespace VRMShaders
{
/// <summary>
/// Unity の ImageConversion.LoadImage を用いて PNG/JPG の読み込みを実現する
/// </summary>
public sealed class UnityTextureDeserializer : ITextureDeserializer
{
public async Task<Texture2D> LoadTextureAsync(byte[] imageData, bool useMipmap, ColorSpace colorSpace)
{
var texture = new Texture2D(2, 2, TextureFormat.ARGB32, useMipmap, colorSpace == ColorSpace.Linear);
if (imageData != null)
{
texture.LoadImage(imageData);
}
return texture;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 170beedd62e24506acc42b7c04464e84
timeCreated: 1622107784

View File

@ -2,7 +2,6 @@
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{

View File

@ -1,7 +1,6 @@
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{