mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-11 13:29:41 -05:00
VRMShaders.TextureFactory
This commit is contained in:
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text;
|
||||
using VRMShaders;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
@@ -44,7 +45,7 @@ namespace UniGLTF
|
||||
IEnumerable<(string, UnityEngine.Object)> externalObjectMap = null)
|
||||
{
|
||||
m_parser = parser;
|
||||
m_textureFactory = new TextureFactory(GLTF, Storage, externalObjectMap);
|
||||
m_textureFactory = new TextureFactory(externalObjectMap);
|
||||
m_materialFactory = new MaterialFactory(m_parser, externalObjectMap);
|
||||
}
|
||||
|
||||
@@ -283,7 +284,7 @@ namespace UniGLTF
|
||||
/// Root ヒエラルキーで使っているリソース
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual void TransferOwnership(TakeOwnershipFunc take)
|
||||
public virtual void TransferOwnership(Func<UnityEngine.Object, bool> take)
|
||||
{
|
||||
var list = new List<UnityEngine.Object>();
|
||||
foreach (var mesh in Meshes)
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace UniGLTF
|
||||
if (m.emissiveTexture != null)
|
||||
{
|
||||
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(m.emissiveTexture);
|
||||
yield return TextureFactory.CreateSRGB(parser, m.emissiveTexture.index, offset, scale);
|
||||
yield return GltfTextureImporter.CreateSRGB(parser, m.emissiveTexture.index, offset, scale);
|
||||
}
|
||||
|
||||
// normal
|
||||
|
||||
@@ -99,9 +99,15 @@ namespace UniGLTF
|
||||
|
||||
/// <summary>
|
||||
/// 所有権(Dispose権)を移譲する
|
||||
///
|
||||
/// 所有権を移動する関数。
|
||||
///
|
||||
/// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる
|
||||
/// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="take"></param>
|
||||
public void TransferOwnership(TakeOwnershipFunc take)
|
||||
public void TransferOwnership(Func<UnityEngine.Object, bool> take)
|
||||
{
|
||||
var list = new List<Material>();
|
||||
foreach (var x in m_materials)
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace UniGLTF
|
||||
public static TextureImportParam BaseColorTexture(GltfParser parser, glTFMaterial src)
|
||||
{
|
||||
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture);
|
||||
return TextureFactory.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale);
|
||||
return GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale);
|
||||
}
|
||||
|
||||
public static TextureImportParam StandardTexture(GltfParser parser, glTFMaterial src)
|
||||
@@ -60,7 +60,7 @@ namespace UniGLTF
|
||||
roughnessFactor = src.pbrMetallicRoughness.roughnessFactor;
|
||||
}
|
||||
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture);
|
||||
return TextureFactory.CreateStandard(parser,
|
||||
return GltfTextureImporter.CreateStandard(parser,
|
||||
src.pbrMetallicRoughness?.metallicRoughnessTexture?.index,
|
||||
src.occlusionTexture?.index,
|
||||
offset, scale,
|
||||
@@ -71,14 +71,14 @@ namespace UniGLTF
|
||||
public static TextureImportParam NormalTexture(GltfParser parser, glTFMaterial src)
|
||||
{
|
||||
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.normalTexture);
|
||||
return TextureFactory.CreateNormal(parser, src.normalTexture.index, offset, scale);
|
||||
return GltfTextureImporter.CreateNormal(parser, src.normalTexture.index, offset, scale);
|
||||
}
|
||||
|
||||
public static async Task<Material> CreateAsync(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture)
|
||||
{
|
||||
if (getTexture == null)
|
||||
{
|
||||
getTexture = (IAwaitCaller _awaitCaller, glTF _gltf, TextureImportParam _param) => Task.FromResult<Texture2D>(null);
|
||||
getTexture = (TextureImportParam _param) => Task.FromResult<Texture2D>(null);
|
||||
}
|
||||
|
||||
var material = new Material(Shader.Find(ShaderName));
|
||||
@@ -106,7 +106,7 @@ namespace UniGLTF
|
||||
if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1)
|
||||
{
|
||||
var param = BaseColorTexture(parser, src);
|
||||
material.mainTexture = await getTexture(awaitCaller, parser.GLTF, param);
|
||||
material.mainTexture = await getTexture(param);
|
||||
|
||||
// Texture Offset and Scale
|
||||
MaterialFactory.SetTextureOffsetAndScale(material, "_MainTex", param.Offset, param.Scale);
|
||||
@@ -116,7 +116,7 @@ namespace UniGLTF
|
||||
{
|
||||
material.EnableKeyword("_METALLICGLOSSMAP");
|
||||
|
||||
var texture = await getTexture(awaitCaller, parser.GLTF, standardParam);
|
||||
var texture = await getTexture(standardParam);
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture(TextureImportParam.METALLIC_GLOSS_PROP, texture);
|
||||
@@ -141,7 +141,7 @@ namespace UniGLTF
|
||||
{
|
||||
material.EnableKeyword("_NORMALMAP");
|
||||
var param = NormalTexture(parser, src);
|
||||
var texture = await getTexture(awaitCaller, parser.GLTF, param);
|
||||
var texture = await getTexture(param);
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture(TextureImportParam.NORMAL_PROP, texture);
|
||||
@@ -154,7 +154,7 @@ namespace UniGLTF
|
||||
|
||||
if (src.occlusionTexture != null && src.occlusionTexture.index != -1)
|
||||
{
|
||||
var texture = await getTexture(awaitCaller, parser.GLTF, standardParam);
|
||||
var texture = await getTexture(standardParam);
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture(TextureImportParam.OCCLUSION_PROP, texture);
|
||||
@@ -180,8 +180,8 @@ namespace UniGLTF
|
||||
if (src.emissiveTexture != null && src.emissiveTexture.index != -1)
|
||||
{
|
||||
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.emissiveTexture);
|
||||
var param = TextureFactory.CreateSRGB(parser, src.emissiveTexture.index, offset, scale);
|
||||
var texture = await getTexture(awaitCaller, parser.GLTF, param);
|
||||
var param = GltfTextureImporter.CreateSRGB(parser, src.emissiveTexture.index, offset, scale);
|
||||
var texture = await getTexture(param);
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture("_EmissionMap", texture);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace UniGLTF
|
||||
{
|
||||
if (getTexture == null)
|
||||
{
|
||||
getTexture = (_x, _y, _z) => Task.FromResult<Texture2D>(default);
|
||||
getTexture = (_) => Task.FromResult<Texture2D>(default);
|
||||
}
|
||||
|
||||
var src = parser.GLTF.materials[i];
|
||||
@@ -23,7 +23,7 @@ namespace UniGLTF
|
||||
if (src.pbrMetallicRoughness.baseColorTexture != null)
|
||||
{
|
||||
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture);
|
||||
material.mainTexture = await getTexture(awaitCaller, parser.GLTF, TextureFactory.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale));
|
||||
material.mainTexture = await getTexture(GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale));
|
||||
|
||||
// Texture Offset and Scale
|
||||
MaterialFactory.SetTextureOffsetAndScale(material, "_MainTex", offset, scale);
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace UniGLTF
|
||||
{
|
||||
/// <summary>
|
||||
/// 所有権を移動する関数。
|
||||
///
|
||||
/// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる
|
||||
/// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="o">対象のオブジェクト</param>
|
||||
/// <returns>所有権が移動したらtrue</returns>
|
||||
public delegate bool TakeOwnershipFunc(UnityEngine.Object o);
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using VRMShaders;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
public delegate Task<Texture2D> GetTextureAsyncFunc(TextureImportParam param);
|
||||
|
||||
/// <summary>
|
||||
/// glTFTexture を TextureImportParam に変換する
|
||||
/// </summary>
|
||||
public static class GltfTextureImporter
|
||||
{
|
||||
static Byte[] ToArray(ArraySegment<byte> bytes)
|
||||
{
|
||||
if (bytes.Array == null)
|
||||
{
|
||||
return new byte[] { };
|
||||
}
|
||||
else if (bytes.Offset == 0 && bytes.Count == bytes.Array.Length)
|
||||
{
|
||||
return bytes.Array;
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte[] result = new byte[bytes.Count];
|
||||
Buffer.BlockCopy(bytes.Array, bytes.Offset, result, 0, result.Length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static TextureImportParam CreateSRGB(GltfParser parser, int textureIndex, Vector2 offset, Vector2 scale)
|
||||
{
|
||||
var name = CreateNameExt(parser.GLTF, textureIndex, TextureImportTypes.sRGB);
|
||||
var sampler = CreateSampler(parser.GLTF, textureIndex);
|
||||
GetTextureBytesAsync getTextureBytesAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, textureIndex)));
|
||||
return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.sRGB, default, default, getTextureBytesAsync, default, default, default, default, default);
|
||||
}
|
||||
|
||||
public static TextureImportParam CreateNormal(GltfParser parser, int textureIndex, Vector2 offset, Vector2 scale)
|
||||
{
|
||||
var name = CreateNameExt(parser.GLTF, textureIndex, TextureImportTypes.NormalMap);
|
||||
var sampler = CreateSampler(parser.GLTF, textureIndex);
|
||||
GetTextureBytesAsync getTextureBytesAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, textureIndex)));
|
||||
return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.NormalMap, default, default, getTextureBytesAsync, default, default, default, default, default);
|
||||
}
|
||||
|
||||
public static TextureImportParam CreateStandard(GltfParser parser, int? metallicRoughnessTextureIndex, int? occlusionTextureIndex, Vector2 offset, Vector2 scale, float metallicFactor, float roughnessFactor)
|
||||
{
|
||||
TextureImportName name = default;
|
||||
|
||||
GetTextureBytesAsync getMetallicRoughnessAsync = default;
|
||||
SamplerParam sampler = default;
|
||||
if (metallicRoughnessTextureIndex.HasValue)
|
||||
{
|
||||
name = CreateNameExt(parser.GLTF, metallicRoughnessTextureIndex.Value, TextureImportTypes.StandardMap);
|
||||
sampler = CreateSampler(parser.GLTF, metallicRoughnessTextureIndex.Value);
|
||||
getMetallicRoughnessAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, metallicRoughnessTextureIndex.Value)));
|
||||
}
|
||||
|
||||
GetTextureBytesAsync getOcclusionAsync = default;
|
||||
if (occlusionTextureIndex.HasValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name.GltfName))
|
||||
{
|
||||
name = CreateNameExt(parser.GLTF, occlusionTextureIndex.Value, TextureImportTypes.StandardMap);
|
||||
}
|
||||
sampler = CreateSampler(parser.GLTF, occlusionTextureIndex.Value);
|
||||
getOcclusionAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, occlusionTextureIndex.Value)));
|
||||
}
|
||||
|
||||
return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.StandardMap, metallicFactor, roughnessFactor, getMetallicRoughnessAsync, getOcclusionAsync, default, default, default, default);
|
||||
}
|
||||
|
||||
public static TextureImportName CreateNameExt(glTF gltf, int textureIndex, TextureImportTypes textureType)
|
||||
{
|
||||
if (textureIndex < 0 || textureIndex >= gltf.textures.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
var gltfTexture = gltf.textures[textureIndex];
|
||||
if (gltfTexture.source < 0 || gltfTexture.source >= gltf.images.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
var gltfImage = gltf.images[gltfTexture.source];
|
||||
return new TextureImportName(textureType, gltfTexture.name, gltfImage.GetExt(), gltfImage.uri);
|
||||
}
|
||||
|
||||
public static SamplerParam CreateSampler(glTF gltf, int index)
|
||||
{
|
||||
var gltfTexture = gltf.textures[index];
|
||||
if (gltfTexture.sampler < 0 || gltfTexture.sampler >= gltf.samplers.Count)
|
||||
{
|
||||
// default
|
||||
return new SamplerParam
|
||||
{
|
||||
FilterMode = FilterMode.Bilinear,
|
||||
WrapModes = new (SamplerWrapType, TextureWrapMode)[] { },
|
||||
};
|
||||
}
|
||||
|
||||
var gltfSampler = gltf.samplers[gltfTexture.sampler];
|
||||
return new SamplerParam
|
||||
{
|
||||
WrapModes = GetUnityWrapMode(gltfSampler).ToArray(),
|
||||
FilterMode = ImportFilterMode(gltfSampler.minFilter),
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<(SamplerWrapType, TextureWrapMode)> GetUnityWrapMode(glTFTextureSampler sampler)
|
||||
{
|
||||
if (sampler.wrapS == sampler.wrapT)
|
||||
{
|
||||
switch (sampler.wrapS)
|
||||
{
|
||||
case glWrap.NONE: // default
|
||||
yield return (SamplerWrapType.All, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.CLAMP_TO_EDGE:
|
||||
yield return (SamplerWrapType.All, TextureWrapMode.Clamp);
|
||||
break;
|
||||
|
||||
case glWrap.REPEAT:
|
||||
yield return (SamplerWrapType.All, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.MIRRORED_REPEAT:
|
||||
yield return (SamplerWrapType.All, TextureWrapMode.Mirror);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (sampler.wrapS)
|
||||
{
|
||||
case glWrap.NONE: // default
|
||||
yield return (SamplerWrapType.U, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.CLAMP_TO_EDGE:
|
||||
yield return (SamplerWrapType.U, TextureWrapMode.Clamp);
|
||||
break;
|
||||
|
||||
case glWrap.REPEAT:
|
||||
yield return (SamplerWrapType.U, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.MIRRORED_REPEAT:
|
||||
yield return (SamplerWrapType.U, TextureWrapMode.Mirror);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
switch (sampler.wrapT)
|
||||
{
|
||||
case glWrap.NONE: // default
|
||||
yield return (SamplerWrapType.V, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.CLAMP_TO_EDGE:
|
||||
yield return (SamplerWrapType.V, TextureWrapMode.Clamp);
|
||||
break;
|
||||
|
||||
case glWrap.REPEAT:
|
||||
yield return (SamplerWrapType.V, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.MIRRORED_REPEAT:
|
||||
yield return (SamplerWrapType.V, TextureWrapMode.Mirror);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static FilterMode ImportFilterMode(glFilter filterMode)
|
||||
{
|
||||
switch (filterMode)
|
||||
{
|
||||
case glFilter.NEAREST:
|
||||
case glFilter.NEAREST_MIPMAP_LINEAR:
|
||||
case glFilter.NEAREST_MIPMAP_NEAREST:
|
||||
return FilterMode.Point;
|
||||
|
||||
case glFilter.NONE:
|
||||
case glFilter.LINEAR:
|
||||
case glFilter.LINEAR_MIPMAP_NEAREST:
|
||||
return FilterMode.Bilinear;
|
||||
|
||||
case glFilter.LINEAR_MIPMAP_LINEAR:
|
||||
return FilterMode.Trilinear;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58277bcba49b13142acfa67d40041970
|
||||
guid: c9128dde9a44e1f43a808330ebfba145
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -1,447 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using VRMShaders;
|
||||
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
[Flags]
|
||||
public enum TextureLoadFlags
|
||||
{
|
||||
None = 0,
|
||||
Used = 1,
|
||||
External = 1 << 1,
|
||||
}
|
||||
|
||||
public struct TextureLoadInfo
|
||||
{
|
||||
public readonly Texture2D Texture;
|
||||
public readonly TextureLoadFlags Flags;
|
||||
public bool IsUsed => Flags.HasFlag(TextureLoadFlags.Used);
|
||||
public bool IsExternal => Flags.HasFlag(TextureLoadFlags.External);
|
||||
|
||||
public bool IsSubAsset => IsUsed && !IsExternal;
|
||||
|
||||
public TextureLoadInfo(Texture2D texture, bool used, bool isExternal)
|
||||
{
|
||||
Texture = texture;
|
||||
var flags = TextureLoadFlags.None;
|
||||
if (used)
|
||||
{
|
||||
flags |= TextureLoadFlags.Used;
|
||||
}
|
||||
if (isExternal)
|
||||
{
|
||||
flags |= TextureLoadFlags.External;
|
||||
}
|
||||
Flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
public delegate Task<Texture2D> GetTextureAsyncFunc(IAwaitCaller awaitCaller, glTF gltf, TextureImportParam param);
|
||||
public class TextureFactory : IDisposable
|
||||
{
|
||||
glTF m_gltf;
|
||||
IStorage m_storage;
|
||||
|
||||
public readonly Dictionary<string, Texture2D> ExternalMap;
|
||||
|
||||
public TextureFactory(glTF gltf, IStorage storage, IEnumerable<(string, UnityEngine.Object)> externalMap)
|
||||
{
|
||||
m_gltf = gltf;
|
||||
m_storage = storage;
|
||||
|
||||
if (externalMap != null)
|
||||
{
|
||||
ExternalMap = externalMap
|
||||
.Select(kv => (kv.Item1, kv.Item2 as Texture2D))
|
||||
.Where(kv => kv.Item2 != null)
|
||||
.ToDictionary(kv => kv.Item1, kv => kv.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Action<UnityEngine.Object> destroy = UnityResourceDestroyer.DestroyResource();
|
||||
foreach (var kv in m_textureCache)
|
||||
{
|
||||
if (!kv.Value.IsExternal)
|
||||
{
|
||||
#if VRM_DEVELOP
|
||||
// Debug.Log($"Destroy {kv.Value.Texture}");
|
||||
#endif
|
||||
destroy(kv.Value.Texture);
|
||||
}
|
||||
}
|
||||
m_textureCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有権(Dispose権)を移譲する
|
||||
/// </summary>
|
||||
/// <param name="take"></param>
|
||||
public void TransferOwnership(TakeOwnershipFunc take)
|
||||
{
|
||||
var keys = new List<string>();
|
||||
foreach (var x in m_textureCache)
|
||||
{
|
||||
if (x.Value.IsUsed && !x.Value.IsExternal)
|
||||
{
|
||||
// マテリアルから参照されていて
|
||||
// 外部のAssetからロードしていない。
|
||||
if (take(x.Value.Texture))
|
||||
{
|
||||
keys.Add(x.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var x in keys)
|
||||
{
|
||||
m_textureCache.Remove(x);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="string"></typeparam>
|
||||
/// <typeparam name="TextureLoadInfo"></typeparam>
|
||||
/// <returns></returns>
|
||||
Dictionary<string, TextureLoadInfo> m_textureCache = new Dictionary<string, TextureLoadInfo>();
|
||||
|
||||
public IEnumerable<TextureLoadInfo> Textures => m_textureCache.Values;
|
||||
|
||||
static Byte[] ToArray(ArraySegment<byte> bytes)
|
||||
{
|
||||
if (bytes.Array == null)
|
||||
{
|
||||
return new byte[] { };
|
||||
}
|
||||
else if (bytes.Offset == 0 && bytes.Count == bytes.Array.Length)
|
||||
{
|
||||
return bytes.Array;
|
||||
}
|
||||
else
|
||||
{
|
||||
Byte[] result = new byte[bytes.Count];
|
||||
Buffer.BlockCopy(bytes.Array, bytes.Offset, result, 0, result.Length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
async Task<TextureLoadInfo> GetOrCreateBaseTexture(IAwaitCaller awaitCaller, TextureImportParam param, GetTextureBytesAsync getTextureBytesAsync, RenderTextureReadWrite colorSpace, bool used)
|
||||
{
|
||||
var name = param.GltfName;
|
||||
if (m_textureCache.TryGetValue(name, out TextureLoadInfo cacheInfo))
|
||||
{
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
// not found. load new
|
||||
var imageBytes = await getTextureBytesAsync();
|
||||
|
||||
//
|
||||
// texture from image(png etc) bytes
|
||||
//
|
||||
var texture = new Texture2D(2, 2, TextureFormat.ARGB32, false, colorSpace == RenderTextureReadWrite.Linear);
|
||||
texture.name = name;
|
||||
if (imageBytes != null)
|
||||
{
|
||||
texture.LoadImage(imageBytes);
|
||||
}
|
||||
|
||||
SetSampler(texture, param);
|
||||
|
||||
cacheInfo = new TextureLoadInfo(texture, used, false);
|
||||
m_textureCache.Add(name, cacheInfo);
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
public static void SetSampler(Texture2D texture, TextureImportParam param)
|
||||
{
|
||||
if (texture == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (key, value) in param.Sampler.WrapModes)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case SamplerWrapType.All:
|
||||
texture.wrapMode = value;
|
||||
break;
|
||||
|
||||
case SamplerWrapType.U:
|
||||
texture.wrapModeU = value;
|
||||
break;
|
||||
|
||||
case SamplerWrapType.V:
|
||||
texture.wrapModeV = value;
|
||||
break;
|
||||
|
||||
case SamplerWrapType.W:
|
||||
texture.wrapModeW = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
texture.filterMode = param.Sampler.FilterMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// テクスチャーをロード、必要であれば変換して返す。
|
||||
/// 同じものはキャッシュを返す
|
||||
/// </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<Texture2D> GetTextureAsync(IAwaitCaller awaitCaller, glTF gltf, TextureImportParam param)
|
||||
{
|
||||
//
|
||||
// ExtractKey で External とのマッチングを試みる
|
||||
//
|
||||
// Normal => GltfName
|
||||
// Standard => ConvertedName
|
||||
// sRGB => GltfName
|
||||
// Linear => GltfName
|
||||
//
|
||||
if (param.Index0 != null && ExternalMap != null)
|
||||
{
|
||||
if (ExternalMap.TryGetValue(param.ExtractKey, out Texture2D external))
|
||||
{
|
||||
return external;
|
||||
}
|
||||
}
|
||||
|
||||
switch (param.TextureType)
|
||||
{
|
||||
case TextureImportTypes.NormalMap:
|
||||
// Runtime/SubAsset 用に変換する
|
||||
{
|
||||
if (!m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo info))
|
||||
{
|
||||
var baseTexture = await GetOrCreateBaseTexture(awaitCaller, param, param.Index0, RenderTextureReadWrite.Linear, false);
|
||||
var converted = NormalConverter.Import(baseTexture.Texture);
|
||||
converted.name = param.ConvertedName;
|
||||
info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(converted.name, info);
|
||||
}
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
case TextureImportTypes.StandardMap:
|
||||
// 変換する
|
||||
{
|
||||
if (!m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo info))
|
||||
{
|
||||
TextureLoadInfo baseTexture = default;
|
||||
if (param.Index0!=null)
|
||||
{
|
||||
baseTexture = await GetOrCreateBaseTexture(awaitCaller, param, param.Index0, RenderTextureReadWrite.Linear, false);
|
||||
}
|
||||
TextureLoadInfo occlusionBaseTexture = default;
|
||||
if (param.Index1!=null)
|
||||
{
|
||||
occlusionBaseTexture = await GetOrCreateBaseTexture(awaitCaller, param, param.Index1, RenderTextureReadWrite.Linear, false);
|
||||
}
|
||||
var converted = OcclusionMetallicRoughnessConverter.Import(baseTexture.Texture, param.MetallicFactor, param.RoughnessFactor, occlusionBaseTexture.Texture);
|
||||
converted.name = param.ConvertedName;
|
||||
info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(converted.name, info);
|
||||
}
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
var baseTexture = await GetOrCreateBaseTexture(awaitCaller, param, param.Index0, RenderTextureReadWrite.sRGB, true);
|
||||
return baseTexture.Texture;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static TextureImportParam CreateSRGB(GltfParser parser, int textureIndex, Vector2 offset, Vector2 scale)
|
||||
{
|
||||
var name = CreateNameExt(parser.GLTF, textureIndex, TextureImportTypes.sRGB);
|
||||
var sampler = CreateSampler(parser.GLTF, textureIndex);
|
||||
GetTextureBytesAsync getTextureBytesAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, textureIndex)));
|
||||
return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.sRGB, default, default, getTextureBytesAsync, default, default, default, default, default);
|
||||
}
|
||||
|
||||
public static TextureImportParam CreateNormal(GltfParser parser, int textureIndex, Vector2 offset, Vector2 scale)
|
||||
{
|
||||
var name = CreateNameExt(parser.GLTF, textureIndex, TextureImportTypes.NormalMap);
|
||||
var sampler = CreateSampler(parser.GLTF, textureIndex);
|
||||
GetTextureBytesAsync getTextureBytesAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, textureIndex)));
|
||||
return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.NormalMap, default, default, getTextureBytesAsync, default, default, default, default, default);
|
||||
}
|
||||
|
||||
public static TextureImportParam CreateStandard(GltfParser parser, int? metallicRoughnessTextureIndex, int? occlusionTextureIndex, Vector2 offset, Vector2 scale, float metallicFactor, float roughnessFactor)
|
||||
{
|
||||
TextureImportName name = default;
|
||||
|
||||
GetTextureBytesAsync getMetallicRoughnessAsync = default;
|
||||
SamplerParam sampler = default;
|
||||
if (metallicRoughnessTextureIndex.HasValue)
|
||||
{
|
||||
name = CreateNameExt(parser.GLTF, metallicRoughnessTextureIndex.Value, TextureImportTypes.StandardMap);
|
||||
sampler = CreateSampler(parser.GLTF, metallicRoughnessTextureIndex.Value);
|
||||
getMetallicRoughnessAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, metallicRoughnessTextureIndex.Value)));
|
||||
}
|
||||
|
||||
GetTextureBytesAsync getOcclusionAsync = default;
|
||||
if (occlusionTextureIndex.HasValue)
|
||||
{
|
||||
if(string.IsNullOrEmpty(name.GltfName)){
|
||||
name = CreateNameExt(parser.GLTF, occlusionTextureIndex.Value, TextureImportTypes.StandardMap);
|
||||
}
|
||||
sampler = CreateSampler(parser.GLTF, occlusionTextureIndex.Value);
|
||||
getOcclusionAsync = () => Task.FromResult(ToArray(parser.GLTF.GetImageBytesFromTextureIndex(parser.Storage, occlusionTextureIndex.Value)));
|
||||
}
|
||||
|
||||
return new TextureImportParam(name, offset, scale, sampler, TextureImportTypes.StandardMap, metallicFactor, roughnessFactor, getMetallicRoughnessAsync, getOcclusionAsync, default, default, default, default);
|
||||
}
|
||||
|
||||
public static TextureImportName CreateNameExt(glTF gltf, int textureIndex, TextureImportTypes textureType)
|
||||
{
|
||||
if (textureIndex < 0 || textureIndex >= gltf.textures.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
var gltfTexture = gltf.textures[textureIndex];
|
||||
if (gltfTexture.source < 0 || gltfTexture.source >= gltf.images.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
var gltfImage = gltf.images[gltfTexture.source];
|
||||
return new TextureImportName(textureType, gltfTexture.name, gltfImage.GetExt(), gltfImage.uri);
|
||||
}
|
||||
|
||||
public static SamplerParam CreateSampler(glTF gltf, int index)
|
||||
{
|
||||
var gltfTexture = gltf.textures[index];
|
||||
if (gltfTexture.sampler < 0 || gltfTexture.sampler >= gltf.samplers.Count)
|
||||
{
|
||||
// default
|
||||
return new SamplerParam
|
||||
{
|
||||
FilterMode = FilterMode.Bilinear,
|
||||
WrapModes = new (SamplerWrapType, TextureWrapMode)[] { },
|
||||
};
|
||||
}
|
||||
|
||||
var gltfSampler = gltf.samplers[gltfTexture.sampler];
|
||||
return new SamplerParam
|
||||
{
|
||||
WrapModes = GetUnityWrapMode(gltfSampler).ToArray(),
|
||||
FilterMode = ImportFilterMode(gltfSampler.minFilter),
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<(SamplerWrapType, TextureWrapMode)> GetUnityWrapMode(glTFTextureSampler sampler)
|
||||
{
|
||||
if (sampler.wrapS == sampler.wrapT)
|
||||
{
|
||||
switch (sampler.wrapS)
|
||||
{
|
||||
case glWrap.NONE: // default
|
||||
yield return (SamplerWrapType.All, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.CLAMP_TO_EDGE:
|
||||
yield return (SamplerWrapType.All, TextureWrapMode.Clamp);
|
||||
break;
|
||||
|
||||
case glWrap.REPEAT:
|
||||
yield return (SamplerWrapType.All, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.MIRRORED_REPEAT:
|
||||
yield return (SamplerWrapType.All, TextureWrapMode.Mirror);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (sampler.wrapS)
|
||||
{
|
||||
case glWrap.NONE: // default
|
||||
yield return (SamplerWrapType.U, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.CLAMP_TO_EDGE:
|
||||
yield return (SamplerWrapType.U, TextureWrapMode.Clamp);
|
||||
break;
|
||||
|
||||
case glWrap.REPEAT:
|
||||
yield return (SamplerWrapType.U, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.MIRRORED_REPEAT:
|
||||
yield return (SamplerWrapType.U, TextureWrapMode.Mirror);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
switch (sampler.wrapT)
|
||||
{
|
||||
case glWrap.NONE: // default
|
||||
yield return (SamplerWrapType.V, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.CLAMP_TO_EDGE:
|
||||
yield return (SamplerWrapType.V, TextureWrapMode.Clamp);
|
||||
break;
|
||||
|
||||
case glWrap.REPEAT:
|
||||
yield return (SamplerWrapType.V, TextureWrapMode.Repeat);
|
||||
break;
|
||||
|
||||
case glWrap.MIRRORED_REPEAT:
|
||||
yield return (SamplerWrapType.V, TextureWrapMode.Mirror);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static FilterMode ImportFilterMode(glFilter filterMode)
|
||||
{
|
||||
switch (filterMode)
|
||||
{
|
||||
case glFilter.NEAREST:
|
||||
case glFilter.NEAREST_MIPMAP_LINEAR:
|
||||
case glFilter.NEAREST_MIPMAP_NEAREST:
|
||||
return FilterMode.Point;
|
||||
|
||||
case glFilter.NONE:
|
||||
case glFilter.LINEAR:
|
||||
case glFilter.LINEAR_MIPMAP_NEAREST:
|
||||
return FilterMode.Bilinear;
|
||||
|
||||
case glFilter.LINEAR_MIPMAP_LINEAR:
|
||||
return FilterMode.Trilinear;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,20 @@ using UniGLTF;
|
||||
using UnityEngine;
|
||||
using VRMShaders;
|
||||
|
||||
|
||||
namespace VRM
|
||||
{
|
||||
public static class VRMTextureParam
|
||||
public static class MToonTextureParam
|
||||
{
|
||||
public static TextureImportParam Create(GltfParser parser, int index, Vector2 offset, Vector2 scale, string prop, float metallicFactor, float roughnessFactor)
|
||||
{
|
||||
switch (prop)
|
||||
{
|
||||
case TextureImportParam.NORMAL_PROP:
|
||||
return TextureFactory.CreateNormal(parser, index, offset, scale);
|
||||
return GltfTextureImporter.CreateNormal(parser, index, offset, scale);
|
||||
|
||||
default:
|
||||
return TextureFactory.CreateSRGB(parser, index, offset, scale);
|
||||
return GltfTextureImporter.CreateSRGB(parser, index, offset, scale);
|
||||
|
||||
case TextureImportParam.OCCLUSION_PROP:
|
||||
case TextureImportParam.METALLIC_GLOSS_PROP:
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab2b998b9235dc94a90ccaf2e40a50a6
|
||||
guid: a7af3a3bafe41a64db660a18b1c25097
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -297,7 +297,7 @@ namespace VRM
|
||||
meta.Title = gltfMeta.title;
|
||||
if (gltfMeta.texture >= 0)
|
||||
{
|
||||
meta.Thumbnail = await TextureFactory.GetTextureAsync(awaitCaller, GLTF, TextureFactory.CreateSRGB(Parser, gltfMeta.texture, Vector2.zero, Vector2.one));
|
||||
meta.Thumbnail = await TextureFactory.GetTextureAsync(GltfTextureImporter.CreateSRGB(Parser, gltfMeta.texture, Vector2.zero, Vector2.one));
|
||||
}
|
||||
meta.AllowedUser = gltfMeta.allowedUser;
|
||||
meta.ViolentUssage = gltfMeta.violentUssage;
|
||||
@@ -311,7 +311,7 @@ namespace VRM
|
||||
return meta;
|
||||
}
|
||||
|
||||
public override void TransferOwnership(TakeOwnershipFunc take)
|
||||
public override void TransferOwnership(Func<UnityEngine.Object, bool> take)
|
||||
{
|
||||
// VRM 固有のリソース(ScriptableObject)
|
||||
if (take(HumanoidAvatar))
|
||||
|
||||
@@ -82,8 +82,8 @@ namespace VRM
|
||||
scale = new Vector2(value[2], value[3]);
|
||||
}
|
||||
|
||||
var param = VRMTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, 1, 1);
|
||||
var texture = await getTexture(awaitCaller, parser.GLTF, param);
|
||||
var param = MToonTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, 1, 1);
|
||||
var texture = await getTexture(param);
|
||||
if (texture != null)
|
||||
{
|
||||
material.SetTexture(kv.Key, texture);
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace VRM
|
||||
}
|
||||
|
||||
// SRGB color or normalmap
|
||||
yield return VRMTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, default, default);
|
||||
yield return MToonTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, default, default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace VRM
|
||||
// thumbnail
|
||||
if (m_vrm.meta != null && m_vrm.meta.texture != -1)
|
||||
{
|
||||
var textureInfo = TextureFactory.CreateSRGB(parser, m_vrm.meta.texture, Vector2.zero, Vector2.one);
|
||||
var textureInfo = GltfTextureImporter.CreateSRGB(parser, m_vrm.meta.texture, Vector2.zero, Vector2.one);
|
||||
if (used.Add(textureInfo.ExtractKey))
|
||||
{
|
||||
yield return textureInfo;
|
||||
|
||||
261
Assets/VRMShaders/Runtime/TextureFactory.cs
Normal file
261
Assets/VRMShaders/Runtime/TextureFactory.cs
Normal file
@@ -0,0 +1,261 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
namespace VRMShaders
|
||||
{
|
||||
[Flags]
|
||||
public enum TextureLoadFlags
|
||||
{
|
||||
None = 0,
|
||||
Used = 1,
|
||||
External = 1 << 1,
|
||||
}
|
||||
|
||||
public struct TextureLoadInfo
|
||||
{
|
||||
public readonly Texture2D Texture;
|
||||
public readonly TextureLoadFlags Flags;
|
||||
public bool IsUsed => Flags.HasFlag(TextureLoadFlags.Used);
|
||||
public bool IsExternal => Flags.HasFlag(TextureLoadFlags.External);
|
||||
|
||||
public bool IsSubAsset => IsUsed && !IsExternal;
|
||||
|
||||
public TextureLoadInfo(Texture2D texture, bool used, bool isExternal)
|
||||
{
|
||||
Texture = texture;
|
||||
var flags = TextureLoadFlags.None;
|
||||
if (used)
|
||||
{
|
||||
flags |= TextureLoadFlags.Used;
|
||||
}
|
||||
if (isExternal)
|
||||
{
|
||||
flags |= TextureLoadFlags.External;
|
||||
}
|
||||
Flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
public class TextureFactory : IDisposable
|
||||
{
|
||||
public readonly Dictionary<string, Texture2D> ExternalMap;
|
||||
|
||||
public TextureFactory(IEnumerable<(string, UnityEngine.Object)> externalMap)
|
||||
{
|
||||
if (externalMap != null)
|
||||
{
|
||||
ExternalMap = externalMap
|
||||
.Select(kv => (kv.Item1, kv.Item2 as Texture2D))
|
||||
.Where(kv => kv.Item2 != null)
|
||||
.ToDictionary(kv => kv.Item1, kv => kv.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
public static Action<UnityEngine.Object> DestroyResource()
|
||||
{
|
||||
Action<UnityEngine.Object> des = (UnityEngine.Object o) => UnityEngine.Object.Destroy(o);
|
||||
Action<UnityEngine.Object> desi = (UnityEngine.Object o) => UnityEngine.Object.DestroyImmediate(o);
|
||||
Action<UnityEngine.Object> func = Application.isPlaying
|
||||
? des
|
||||
: desi
|
||||
;
|
||||
return func;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Action<UnityEngine.Object> destroy = DestroyResource();
|
||||
foreach (var kv in m_textureCache)
|
||||
{
|
||||
if (!kv.Value.IsExternal)
|
||||
{
|
||||
#if VRM_DEVELOP
|
||||
// Debug.Log($"Destroy {kv.Value.Texture}");
|
||||
#endif
|
||||
destroy(kv.Value.Texture);
|
||||
}
|
||||
}
|
||||
m_textureCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有権(Dispose権)を移譲する
|
||||
/// </summary>
|
||||
/// <param name="take"></param>
|
||||
public void TransferOwnership(Func<UnityEngine.Object, bool> take)
|
||||
{
|
||||
var keys = new List<string>();
|
||||
foreach (var x in m_textureCache)
|
||||
{
|
||||
if (x.Value.IsUsed && !x.Value.IsExternal)
|
||||
{
|
||||
// マテリアルから参照されていて
|
||||
// 外部のAssetからロードしていない。
|
||||
if (take(x.Value.Texture))
|
||||
{
|
||||
keys.Add(x.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var x in keys)
|
||||
{
|
||||
m_textureCache.Remove(x);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="string"></typeparam>
|
||||
/// <typeparam name="TextureLoadInfo"></typeparam>
|
||||
/// <returns></returns>
|
||||
Dictionary<string, TextureLoadInfo> m_textureCache = new Dictionary<string, TextureLoadInfo>();
|
||||
|
||||
public IEnumerable<TextureLoadInfo> Textures => m_textureCache.Values;
|
||||
|
||||
|
||||
async Task<TextureLoadInfo> GetOrCreateBaseTexture(TextureImportParam param, GetTextureBytesAsync getTextureBytesAsync, RenderTextureReadWrite colorSpace, bool used)
|
||||
{
|
||||
var name = param.GltfName;
|
||||
if (m_textureCache.TryGetValue(name, out TextureLoadInfo cacheInfo))
|
||||
{
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
// not found. load new
|
||||
var imageBytes = await getTextureBytesAsync();
|
||||
|
||||
//
|
||||
// texture from image(png etc) bytes
|
||||
//
|
||||
var texture = new Texture2D(2, 2, TextureFormat.ARGB32, false, colorSpace == RenderTextureReadWrite.Linear);
|
||||
texture.name = name;
|
||||
if (imageBytes != null)
|
||||
{
|
||||
texture.LoadImage(imageBytes);
|
||||
}
|
||||
|
||||
SetSampler(texture, param);
|
||||
|
||||
cacheInfo = new TextureLoadInfo(texture, used, false);
|
||||
m_textureCache.Add(name, cacheInfo);
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
public static void SetSampler(Texture2D texture, TextureImportParam param)
|
||||
{
|
||||
if (texture == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (key, value) in param.Sampler.WrapModes)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case SamplerWrapType.All:
|
||||
texture.wrapMode = value;
|
||||
break;
|
||||
|
||||
case SamplerWrapType.U:
|
||||
texture.wrapModeU = value;
|
||||
break;
|
||||
|
||||
case SamplerWrapType.V:
|
||||
texture.wrapModeV = value;
|
||||
break;
|
||||
|
||||
case SamplerWrapType.W:
|
||||
texture.wrapModeW = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
texture.filterMode = param.Sampler.FilterMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// テクスチャーをロード、必要であれば変換して返す。
|
||||
/// 同じものはキャッシュを返す
|
||||
/// </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<Texture2D> GetTextureAsync(TextureImportParam param)
|
||||
{
|
||||
//
|
||||
// ExtractKey で External とのマッチングを試みる
|
||||
//
|
||||
// Normal => GltfName
|
||||
// Standard => ConvertedName
|
||||
// sRGB => GltfName
|
||||
// Linear => GltfName
|
||||
//
|
||||
if (param.Index0 != null && ExternalMap != null)
|
||||
{
|
||||
if (ExternalMap.TryGetValue(param.ExtractKey, out Texture2D external))
|
||||
{
|
||||
return external;
|
||||
}
|
||||
}
|
||||
|
||||
switch (param.TextureType)
|
||||
{
|
||||
case TextureImportTypes.NormalMap:
|
||||
// Runtime/SubAsset 用に変換する
|
||||
{
|
||||
if (!m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo info))
|
||||
{
|
||||
var baseTexture = await GetOrCreateBaseTexture(param, param.Index0, RenderTextureReadWrite.Linear, false);
|
||||
var converted = NormalConverter.Import(baseTexture.Texture);
|
||||
converted.name = param.ConvertedName;
|
||||
info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(converted.name, info);
|
||||
}
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
case TextureImportTypes.StandardMap:
|
||||
// 変換する
|
||||
{
|
||||
if (!m_textureCache.TryGetValue(param.ConvertedName, out TextureLoadInfo info))
|
||||
{
|
||||
TextureLoadInfo baseTexture = default;
|
||||
if (param.Index0!=null)
|
||||
{
|
||||
baseTexture = await GetOrCreateBaseTexture(param, param.Index0, RenderTextureReadWrite.Linear, false);
|
||||
}
|
||||
TextureLoadInfo occlusionBaseTexture = default;
|
||||
if (param.Index1!=null)
|
||||
{
|
||||
occlusionBaseTexture = await GetOrCreateBaseTexture(param, param.Index1, RenderTextureReadWrite.Linear, false);
|
||||
}
|
||||
var converted = OcclusionMetallicRoughnessConverter.Import(baseTexture.Texture, param.MetallicFactor, param.RoughnessFactor, occlusionBaseTexture.Texture);
|
||||
converted.name = param.ConvertedName;
|
||||
info = new TextureLoadInfo(converted, true, false);
|
||||
m_textureCache.Add(converted.name, info);
|
||||
}
|
||||
return info.Texture;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
var baseTexture = await GetOrCreateBaseTexture(param, param.Index0, RenderTextureReadWrite.sRGB, true);
|
||||
return baseTexture.Texture;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user