Merge pull request #963 from Santarh/refactorTextureExporter

Even if the texture instance is the same, if the color space required by the glTF specification is different, it will be output as a different texture.
This commit is contained in:
ousttrue 2021-05-21 12:45:53 +09:00 committed by GitHub
commit 49e1ea3f02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 165 additions and 154 deletions

View File

@ -15,12 +15,12 @@ namespace UniGLTF
public interface IMaterialExporter
{
glTFMaterial ExportMaterial(Material m, TextureExporter textureExporter);
glTFMaterial ExportMaterial(Material m, ITextureExporter textureExporter);
}
public class MaterialExporter : IMaterialExporter
{
public virtual glTFMaterial ExportMaterial(Material m, TextureExporter textureExporter)
public virtual glTFMaterial ExportMaterial(Material m, ITextureExporter textureExporter)
{
var material = CreateMaterial(m);
@ -34,7 +34,7 @@ namespace UniGLTF
return material;
}
static void Export_Color(Material m, TextureExporter textureManager, glTFMaterial material)
static void Export_Color(Material m, ITextureExporter textureManager, glTFMaterial material)
{
if (m.HasProperty("_Color"))
{
@ -43,7 +43,7 @@ namespace UniGLTF
if (m.HasProperty("_MainTex"))
{
var index = textureManager.ExportSRGB(m.GetTexture("_MainTex"));
var index = textureManager.ExportAsSRgb(m.GetTexture("_MainTex"));
if (index != -1)
{
material.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo()
@ -60,9 +60,9 @@ namespace UniGLTF
/// Occlusion, Metallic, Roughness
/// </summary>
/// <param name="m"></param>
/// <param name="textureManager"></param>
/// <param name="textureExporter"></param>
/// <param name="material"></param>
static void Export_OcclusionMetallicRoughness(Material m, TextureExporter textureManager, glTFMaterial material)
static void Export_OcclusionMetallicRoughness(Material m, ITextureExporter textureExporter, glTFMaterial material)
{
Texture metallicSmoothTexture = default;
float smoothness = 1.0f;
@ -88,7 +88,7 @@ namespace UniGLTF
}
}
int index = textureManager.ExportMetallicSmoothnessOcclusion(metallicSmoothTexture, smoothness, occlusionTexture);
int index = textureExporter.ExportAsGltfMetallicSmoothnessOcclusionCombined(metallicSmoothTexture, smoothness, occlusionTexture);
if (index != -1 && metallicSmoothTexture != null)
{
@ -127,11 +127,11 @@ namespace UniGLTF
}
}
static void Export_Normal(Material m, TextureExporter textureManager, glTFMaterial material)
static void Export_Normal(Material m, ITextureExporter textureExporter, glTFMaterial material)
{
if (m.HasProperty("_BumpMap"))
{
var index = textureManager.ExportNormal(m.GetTexture("_BumpMap"));
var index = textureExporter.ExportAsNormal(m.GetTexture("_BumpMap"));
if (index != -1)
{
material.normalTexture = new glTFMaterialNormalTextureInfo()
@ -149,7 +149,7 @@ namespace UniGLTF
}
}
static void Export_Emission(Material m, TextureExporter textureManager, glTFMaterial material)
static void Export_Emission(Material m, ITextureExporter textureExporter, glTFMaterial material)
{
if (m.IsKeywordEnabled("_EMISSION") == false)
return;
@ -166,7 +166,7 @@ namespace UniGLTF
if (m.HasProperty("_EmissionMap"))
{
var index = textureManager.ExportSRGB(m.GetTexture("_EmissionMap"));
var index = textureExporter.ExportAsSRgb(m.GetTexture("_EmissionMap"));
if (index != -1)
{
material.emissiveTexture = new glTFMaterialEmissiveTextureInfo()

View File

@ -43,7 +43,11 @@ namespace UniGLTF
private set;
}
public TextureExporter TextureManager;
public TextureExporter TextureExporter
{
get;
private set;
}
protected virtual IMaterialExporter CreateMaterialExporter()
{
@ -238,10 +242,10 @@ namespace UniGLTF
#region Materials and Textures
Materials = uniqueUnityMeshes.SelectMany(x => x.Renderer.sharedMaterials).Where(x => x != null).Distinct().ToList();
TextureManager = new TextureExporter(textureSerializer);
TextureExporter = new TextureExporter(textureSerializer);
var materialExporter = CreateMaterialExporter();
glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureManager)).ToList();
glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureExporter)).ToList();
#endregion
#region Meshes
@ -360,9 +364,9 @@ namespace UniGLTF
ExportExtensions(textureSerializer);
// Extension で Texture が増える場合があるので最後に呼ぶ
for (int i = 0; i < TextureManager.Exported.Count; ++i)
for (int i = 0; i < TextureExporter.Exported.Count; ++i)
{
var (unityTexture, colorSpace) = TextureManager.Exported[i];
var (unityTexture, colorSpace) = TextureExporter.Exported[i];
glTF.PushGltfTexture(bufferIndex, unityTexture, colorSpace, textureSerializer);
}
}

View File

@ -18,7 +18,7 @@ namespace UniGLTF
filterMode = FilterMode.Bilinear,
};
var textureManager = new TextureExporter(new EditorTextureSerializer());
var textureExporter = new TextureExporter(new EditorTextureSerializer());
var srcMaterial = new Material(Shader.Find("Standard"));
var offset = new Vector2(0.3f, 0.2f);
@ -29,7 +29,7 @@ namespace UniGLTF
srcMaterial.mainTextureScale = scale;
var materialExporter = new MaterialExporter();
var gltfMaterial = materialExporter.ExportMaterial(srcMaterial, textureManager);
var gltfMaterial = materialExporter.ExportMaterial(srcMaterial, textureExporter);
gltfMaterial.pbrMetallicRoughness.baseColorTexture.extensions = gltfMaterial.pbrMetallicRoughness.baseColorTexture.extensions.Deserialize();
Assert.IsTrue(glTF_KHR_texture_transform.TryGet(gltfMaterial.pbrMetallicRoughness.baseColorTexture, out glTF_KHR_texture_transform t));
@ -242,8 +242,8 @@ namespace UniGLTF
material.SetColor("_EmissionColor", new Color(0, 1, 2, 1));
material.EnableKeyword("_EMISSION");
var materialExporter = new MaterialExporter();
var textureExportManager = new TextureExporter(new EditorTextureSerializer());
var gltfMaterial = materialExporter.ExportMaterial(material, textureExportManager);
var textureExporter = new TextureExporter(new EditorTextureSerializer());
var gltfMaterial = materialExporter.ExportMaterial(material, textureExporter);
Assert.AreEqual(gltfMaterial.emissiveFactor, new float[] { 0, 0.5f, 1 });
}

View File

@ -18,15 +18,15 @@ namespace UniGLTF
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Trilinear,
};
var textureManager = new TextureExporter(new EditorTextureSerializer());
var textureExporter = new TextureExporter(new EditorTextureSerializer());
var material = new Material(Shader.Find("Standard"));
material.mainTexture = tex0;
var materialExporter = new MaterialExporter();
materialExporter.ExportMaterial(material, textureManager);
materialExporter.ExportMaterial(material, textureExporter);
var (convTex0, colorSpace) = textureManager.Exported[0];
var (convTex0, colorSpace) = textureExporter.Exported[0];
var sampler = TextureSamplerUtil.Export(convTex0);
Assert.AreEqual(glWrap.CLAMP_TO_EDGE, sampler.wrapS);

View File

@ -11,8 +11,8 @@ namespace VRM.Samples
{
var material = Resources.Load<Material>(resourceName);
var exporter = new VRMMaterialExporter();
var textureManager = new TextureExporter(new EditorTextureSerializer());
var exported = exporter.ExportMaterial(material, textureManager);
var textureExporter = new TextureExporter(new EditorTextureSerializer());
var exported = exporter.ExportMaterial(material, textureExporter);
// parse glTFExtensionExport to glTFExtensionImport
exported.extensions = exported.extensions.Deserialize();

View File

@ -136,7 +136,7 @@ namespace VRM
VRM.meta.title = meta.Title;
if (meta.Thumbnail != null)
{
VRM.meta.texture = TextureManager.ExportSRGB(meta.Thumbnail);
VRM.meta.texture = TextureExporter.ExportAsSRgb(meta.Thumbnail);
}
// ussage permission
@ -199,7 +199,7 @@ namespace VRM
// materials
foreach (var m in Materials)
{
VRM.materialProperties.Add(VRMMaterialExporter.CreateFromMaterial(m, TextureManager));
VRM.materialProperties.Add(VRMMaterialExporter.CreateFromMaterial(m, TextureExporter));
}
// Serialize VRM

View File

@ -126,7 +126,7 @@ namespace VRM
// "Queue",
};
public static glTF_VRM_Material CreateFromMaterial(Material m, TextureExporter textureExporter)
public static glTF_VRM_Material CreateFromMaterial(Material m, ITextureExporter textureExporter)
{
var material = new glTF_VRM_Material
{
@ -181,8 +181,8 @@ namespace VRM
if (texture != null)
{
var value = kv.Key == "_BumpMap"
? textureExporter.ExportNormal(texture)
: textureExporter.ExportSRGB(texture)
? textureExporter.ExportAsNormal(texture)
: textureExporter.ExportAsSRgb(texture)
;
if (value == -1)
{

View File

@ -18,7 +18,7 @@ namespace VRM
filterMode = FilterMode.Bilinear,
};
var textureManager = new TextureExporter(new EditorTextureSerializer());
var textureExporter = new TextureExporter(new EditorTextureSerializer());
var srcMaterial = new Material(Shader.Find("VRM/MToon"));
var offset = new Vector2(0.3f, 0.2f);
@ -29,7 +29,7 @@ namespace VRM
srcMaterial.mainTextureScale = scale;
var materialExporter = new VRMMaterialExporter();
var vrmMaterial = VRMMaterialExporter.CreateFromMaterial(srcMaterial, textureManager);
var vrmMaterial = VRMMaterialExporter.CreateFromMaterial(srcMaterial, textureExporter);
Assert.AreEqual(vrmMaterial.vectorProperties["_MainTex"], new float[] { 0.3f, 0.2f, 0.5f, 0.6f });
var materialImporter = new VRMMaterialImporter(new glTF_VRM_extensions

View File

@ -12,7 +12,7 @@ namespace UniVRM10
{
public static class Vrm10MToonMaterialExporter
{
public static bool TryExportMaterialAsMToon(Material src, TextureExporter textureExporter, out glTFMaterial dst)
public static bool TryExportMaterialAsMToon(Material src, ITextureExporter textureExporter, out glTFMaterial dst)
{
try
{
@ -41,13 +41,13 @@ namespace UniVRM10
baseColorFactor = def.Color.LitColor.ToFloat4(ColorSpace.sRGB, ColorSpace.Linear),
baseColorTexture = new glTFMaterialBaseColorTextureInfo
{
index = textureExporter.ExportSRGB(def.Color.LitMultiplyTexture),
index = textureExporter.ExportAsSRgb(def.Color.LitMultiplyTexture),
},
},
normalTexture = new glTFMaterialNormalTextureInfo
{
index = textureExporter.ExportNormal(def.Lighting.Normal.NormalTexture),
index = textureExporter.ExportAsNormal(def.Lighting.Normal.NormalTexture),
scale = def.Lighting.Normal.NormalScaleValue,
},
@ -55,7 +55,7 @@ namespace UniVRM10
emissiveFactor = def.Emission.EmissionColor.ToFloat3(ColorSpace.Linear, ColorSpace.Linear),
emissiveTexture = new glTFMaterialEmissiveTextureInfo
{
index = textureExporter.ExportSRGB(def.Emission.EmissionMultiplyTexture),
index = textureExporter.ExportAsSRgb(def.Emission.EmissionMultiplyTexture),
},
};
@ -75,7 +75,7 @@ namespace UniVRM10
ShadeColorFactor = def.Color.ShadeColor.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear),
ShadeMultiplyTexture = new TextureInfo
{
Index = textureExporter.ExportSRGB(def.Color.ShadeMultiplyTexture),
Index = textureExporter.ExportAsSRgb(def.Color.ShadeMultiplyTexture),
},
ShadingToonyFactor = def.Lighting.LitAndShadeMixing.ShadingToonyValue,
ShadingShiftFactor = def.Lighting.LitAndShadeMixing.ShadingShiftValue,
@ -87,14 +87,14 @@ namespace UniVRM10
// Rim Lighting
MatcapTexture = new TextureInfo
{
Index = textureExporter.ExportSRGB(def.MatCap.AdditiveTexture),
Index = textureExporter.ExportAsSRgb(def.MatCap.AdditiveTexture),
},
ParametricRimColorFactor = def.Rim.RimColor.ToFloat3(ColorSpace.Linear, ColorSpace.Linear),
ParametricRimFresnelPowerFactor = def.Rim.RimFresnelPowerValue,
ParametricRimLiftFactor = def.Rim.RimLiftValue,
RimMultiplyTexture = new TextureInfo
{
Index = textureExporter.ExportSRGB(def.Rim.RimMultiplyTexture),
Index = textureExporter.ExportAsSRgb(def.Rim.RimMultiplyTexture),
},
RimLightingMixFactor = def.Rim.RimLightingMixValue,
@ -103,7 +103,7 @@ namespace UniVRM10
OutlineWidthFactor = def.Outline.OutlineWidthValue * centimeterToMeter,
OutlineWidthMultiplyTexture = new TextureInfo
{
Index = textureExporter.ExportLinear(def.Outline.OutlineWidthMultiplyTexture),
Index = textureExporter.ExportAsLinear(def.Outline.OutlineWidthMultiplyTexture),
},
OutlineColorFactor = def.Outline.OutlineColor.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear),
OutlineLightingMixFactor = ExportOutlineLightingMixFactor(def.Outline.OutlineColorMode, def.Outline.OutlineLightingMixValue),
@ -111,7 +111,7 @@ namespace UniVRM10
// UV Anim
UvAnimationMaskTexture = new TextureInfo
{
Index = textureExporter.ExportLinear(def.TextureOption.UvAnimationMaskTexture),
Index = textureExporter.ExportAsLinear(def.TextureOption.UvAnimationMaskTexture),
},
UvAnimationScrollXSpeedFactor = def.TextureOption.UvAnimationScrollXSpeedValue,
UvAnimationScrollYSpeedFactor = def.TextureOption.UvAnimationScrollYSpeedValue * invertY,

View File

@ -651,7 +651,7 @@ namespace UniVRM10
int? thumbnailTextureIndex = default;
if (meta.Thumbnail != null)
{
thumbnailTextureIndex = m_textureExporter.ExportSRGB(meta.Thumbnail);
thumbnailTextureIndex = m_textureExporter.ExportAsSRgb(meta.Thumbnail);
}
return thumbnailTextureIndex;
}

View File

@ -6,7 +6,7 @@ namespace UniVRM10
{
public class Vrm10MaterialExporter : MaterialExporter
{
public override glTFMaterial ExportMaterial(Material m, TextureExporter textureExporter)
public override glTFMaterial ExportMaterial(Material m, ITextureExporter textureExporter)
{
if (Vrm10MToonMaterialExporter.TryExportMaterialAsMToon(m, textureExporter, out var dst))
{

View File

@ -44,7 +44,7 @@ namespace VRMShaders
public (byte[] bytes, string mime) ExportBytesWithMime(Texture2D texture, ColorSpace textureColorSpace)
{
if (TryGetBytesWithMime(texture, out byte[] bytes, out string mime))
if (CanExportAsEditorAssetFile(texture) && TryGetBytesWithMime(texture, out byte[] bytes, out string mime))
{
return (bytes, mime);
}

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
using UnityEngine;
namespace VRMShaders
{
/// <summary>
/// Texture を用途別に変換の要不要を判断して gltf.textures の index に対応させる機能。
///
/// glTF 拡張で Texture の用途を増やす必要がある場合は、この interface を継承して実装すればよい。
/// </summary>
public interface ITextureExporter
{
/// <summary>
/// Export する Texture2D のリスト。これが gltf.textures になる
/// </summary>
IReadOnlyList<(Texture2D, UniGLTF.ColorSpace)> Exported { get; }
/// <summary>
/// 指定の Texture を、 sRGB 色空間の値を持つ Texture に出力するように指示する。
/// </summary>
int ExportAsSRgb(Texture src);
/// <summary>
/// 指定の Texture を、 Linear の値を持つ Texture に出力するように指示する。
/// </summary>
int ExportAsLinear(Texture src);
/// <summary>
/// 指定の Metallic, Roughness, Occlusion 情報を、 glTF 仕様に準拠した 1 枚の合成テクスチャとして出力するように指示する。
/// </summary>
int ExportAsGltfMetallicSmoothnessOcclusionCombined(Texture metallicSmoothTexture, float smoothness, Texture occlusionTexture);
/// <summary>
/// 指定の Texture を、glTF 仕様に準拠した Normal Texture に出力するように指示する。
/// </summary>
int ExportAsNormal(Texture src);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4e22c9906e3e42038724e1bcf46450bf
timeCreated: 1621507967

View File

@ -2,17 +2,20 @@
namespace UniGLTF
{
/// <summary>
/// Texture2D を入力として byte[] を得る機能
/// </summary>
public interface ITextureSerializer
{
/// <summary>
/// Texture をファイルのバイト列そのまま出力してよいかどうか判断するデリゲート
/// Texture をファイルのバイト列そのまま出力してよいかどうか判断する
///
/// Runtime 出力では常に false が望ましい。
/// </summary>
bool CanExportAsEditorAssetFile(Texture texture);
/// <summary>
/// Texture2D から実際のバイト列を取得するデリゲート
/// Texture2D から実際のバイト列を取得する
///
/// textureColorSpace はその Texture2D がアサインされる glTF プロパティの仕様が定める色空間を指定する。
/// 具体的には Texture2D をコピーする際に、コピー先の Texture2D の色空間を決定するために使用する。

View File

@ -1,4 +1,5 @@
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
@ -35,14 +36,14 @@ namespace VRMShaders
// ConvertToNormalValueFromRawColorWhenCompressionIsRequired
public static Texture2D Import(Texture2D texture)
{
return TextureConverter.Convert(texture, TextureImportTypes.NormalMap, null, Encoder);
return TextureConverter.Convert(texture, ColorSpace.Linear, null, Encoder);
}
// Unity texture to GLTF data
// ConvertToRawColorWhenNormalValueIsCompressed
public static Texture2D Export(Texture texture)
{
return TextureConverter.Convert(texture, TextureImportTypes.NormalMap, null, Decoder);
return TextureConverter.Convert(texture, ColorSpace.Linear, null, Decoder);
}
}
}

View File

@ -1,24 +1,25 @@
using System;
using System.Linq;
using UnityEngine;
using ColorSpace = UniGLTF.ColorSpace;
namespace VRMShaders
{
/// <summary>
///
/// * https://github.com/vrm-c/UniVRM/issues/781
///
///
/// * https://github.com/vrm-c/UniVRM/issues/781
///
/// Unity = glTF
/// Occlusion: unity.g = glTF.r
/// Roughness: unity.a = 1 - glTF.g * roughnessFactor
/// Metallic : unity.r = glTF.b * metallicFactor
///
///
/// glTF = Unity
/// Occlusion: glTF.r = unity.g
/// Roughness: glTF.g = 1 - unity.a * smoothness
/// Metallic : glTF.b = unity.r
///
///
/// </summary>
public static class OcclusionMetallicRoughnessConverter
{
@ -29,7 +30,7 @@ namespace VRMShaders
{
if (metallicRoughnessTexture == occlusionTexture)
{
var copyMetallicRoughness = TextureConverter.CopyTexture(metallicRoughnessTexture, TextureImportTypes.StandardMap, null);
var copyMetallicRoughness = TextureConverter.CopyTexture(metallicRoughnessTexture, ColorSpace.Linear, null);
var metallicRoughnessPixels = copyMetallicRoughness.GetPixels32();
for (int i = 0; i < metallicRoughnessPixels.Length; ++i)
{
@ -42,9 +43,9 @@ namespace VRMShaders
}
else
{
var copyMetallicRoughness = TextureConverter.CopyTexture(metallicRoughnessTexture, TextureImportTypes.StandardMap, null);
var copyMetallicRoughness = TextureConverter.CopyTexture(metallicRoughnessTexture, ColorSpace.Linear, null);
var metallicRoughnessPixels = copyMetallicRoughness.GetPixels32();
var copyOcclusion = TextureConverter.CopyTexture(occlusionTexture, TextureImportTypes.StandardMap, null);
var copyOcclusion = TextureConverter.CopyTexture(occlusionTexture, ColorSpace.Linear, null);
var occlusionPixels = copyOcclusion.GetPixels32();
if (metallicRoughnessPixels.Length != occlusionPixels.Length)
{
@ -62,7 +63,7 @@ namespace VRMShaders
}
else if (metallicRoughnessTexture != null)
{
var copyTexture = TextureConverter.CopyTexture(metallicRoughnessTexture, TextureImportTypes.StandardMap, null);
var copyTexture = TextureConverter.CopyTexture(metallicRoughnessTexture, ColorSpace.Linear, null);
copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => ImportPixel(x, metallicFactor, roughnessFactor, default)).ToArray());
copyTexture.Apply();
copyTexture.name = metallicRoughnessTexture.name;
@ -70,7 +71,7 @@ namespace VRMShaders
}
else if (occlusionTexture != null)
{
var copyTexture = TextureConverter.CopyTexture(occlusionTexture, TextureImportTypes.StandardMap, null);
var copyTexture = TextureConverter.CopyTexture(occlusionTexture, ColorSpace.Linear, null);
copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => ImportPixel(default, metallicFactor, roughnessFactor, x)).ToArray());
copyTexture.Apply();
copyTexture.name = occlusionTexture.name;
@ -88,7 +89,7 @@ namespace VRMShaders
{
r = (byte)(metallicRoughness.b * metallicFactor), // Metallic
g = occlusion.r, // Occlusion
b = 0, // not used
b = 0, // not used
a = (byte)(255 - metallicRoughness.g * roughnessFactor), // Roughness to Smoothness
};
@ -101,7 +102,7 @@ namespace VRMShaders
{
if (metallicSmoothTexture == occlusionTexture)
{
var copyTexture = TextureConverter.CopyTexture(metallicSmoothTexture, TextureImportTypes.StandardMap, null);
var copyTexture = TextureConverter.CopyTexture(metallicSmoothTexture, ColorSpace.Linear, null);
copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => ExportPixel(x, smoothness, x)).ToArray());
copyTexture.Apply();
copyTexture.name = metallicSmoothTexture.name;
@ -109,9 +110,9 @@ namespace VRMShaders
}
else
{
var copyMetallicSmooth = TextureConverter.CopyTexture(metallicSmoothTexture, TextureImportTypes.StandardMap, null);
var copyMetallicSmooth = TextureConverter.CopyTexture(metallicSmoothTexture, ColorSpace.Linear, null);
var metallicSmoothPixels = copyMetallicSmooth.GetPixels32();
var copyOcclusion = TextureConverter.CopyTexture(occlusionTexture, TextureImportTypes.StandardMap, null);
var copyOcclusion = TextureConverter.CopyTexture(occlusionTexture, ColorSpace.Linear, null);
var occlusionPixels = copyOcclusion.GetPixels32();
if (metallicSmoothPixels.Length != occlusionPixels.Length)
{
@ -129,7 +130,7 @@ namespace VRMShaders
}
else if (metallicSmoothTexture)
{
var copyTexture = TextureConverter.CopyTexture(metallicSmoothTexture, TextureImportTypes.StandardMap, null);
var copyTexture = TextureConverter.CopyTexture(metallicSmoothTexture, ColorSpace.Linear, null);
copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => ExportPixel(x, smoothness, default)).ToArray());
copyTexture.Apply();
copyTexture.name = metallicSmoothTexture.name;
@ -137,7 +138,7 @@ namespace VRMShaders
}
else if (occlusionTexture)
{
var copyTexture = TextureConverter.CopyTexture(occlusionTexture, TextureImportTypes.StandardMap, null);
var copyTexture = TextureConverter.CopyTexture(occlusionTexture, ColorSpace.Linear, null);
copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => ExportPixel(default, smoothness, x)).ToArray());
copyTexture.Apply();
copyTexture.name = occlusionTexture.name;
@ -153,7 +154,7 @@ namespace VRMShaders
{
var dst = new Color32
{
r = occlusion.g, // Occlusion
r = occlusion.g, // Occlusion
g = (byte)(255 - metallicSmooth.a * smoothness), // Roughness from Smoothness
b = metallicSmooth.r, // Metallic
a = 255, // not used

View File

@ -10,9 +10,9 @@ namespace VRMShaders
{
public delegate Color32 ColorConversion(Color32 color);
public static Texture2D Convert(Texture texture, TextureImportTypes textureType, ColorConversion colorConversion, Material convertMaterial)
public static Texture2D Convert(Texture texture, ColorSpace dstColorSpace, ColorConversion colorConversion, Material convertMaterial)
{
var copyTexture = CopyTexture(texture, textureType, convertMaterial);
var copyTexture = CopyTexture(texture, dstColorSpace, convertMaterial);
if (colorConversion != null)
{
copyTexture.SetPixels32(copyTexture.GetPixels32().Select(x => colorConversion(x)).ToArray());
@ -22,16 +22,11 @@ namespace VRMShaders
return copyTexture;
}
public static Texture2D CopyTexture(Texture src, TextureImportTypes textureType, Material material)
{
return CopyTexture(src, textureType.GetColorSpace(), material);
}
public static Texture2D CopyTexture(Texture src, ColorSpace colorSpace, Material material)
public static Texture2D CopyTexture(Texture src, ColorSpace dstColorSpace, Material material)
{
Texture2D dst = null;
RenderTextureReadWrite readWrite;
switch (colorSpace)
switch (dstColorSpace)
{
case ColorSpace.sRGB:
readWrite = RenderTextureReadWrite.sRGB;
@ -40,7 +35,7 @@ namespace VRMShaders
readWrite = RenderTextureReadWrite.Linear;
break;
default:
throw new ArgumentOutOfRangeException(nameof(colorSpace), colorSpace, null);
throw new ArgumentOutOfRangeException(nameof(dstColorSpace), dstColorSpace, null);
}
var renderTexture = new RenderTexture(src.width, src.height, 0, RenderTextureFormat.ARGB32, readWrite);
@ -78,4 +73,4 @@ namespace VRMShaders
return dst;
}
}
}
}

View File

@ -11,9 +11,13 @@ namespace VRMShaders
/// glTF にエクスポートする Texture2D を蓄えて index を確定させる。
/// Exporter の最後でまとめて Texture2D から bytes 列を得て出力する。
/// </summary>
public class TextureExporter : IDisposable
public sealed class TextureExporter : IDisposable, ITextureExporter
{
private ITextureSerializer m_textureSerializer;
private readonly ITextureSerializer m_textureSerializer;
private readonly Dictionary<ExportKey, int> m_exportMap = new Dictionary<ExportKey, int>();
private readonly List<(Texture2D, ColorSpace)> m_exported = new List<(Texture2D, ColorSpace)>();
public IReadOnlyList<(Texture2D, ColorSpace)> Exported => m_exported;
public TextureExporter(ITextureSerializer textureSerializer)
{
@ -25,22 +29,24 @@ namespace VRMShaders
// TODO: export 用にコピー・変換したテクスチャーをここで解放したい
}
public enum ConvertTypes
enum ExportTypes
{
// 無変換
None,
// sRGB テクスチャとして出力
Srgb,
// Linear テクスチャとして出力
Linear,
// Unity Standard様式 から glTF PBR様式への変換
OcclusionMetallicRoughness,
// Assetを使うときはそのバイト列を無変換で、それ以外は DXT5nm 形式からのデコードを行う
Normal,
}
struct ExportKey
readonly struct ExportKey
{
public readonly Texture Src;
public readonly ConvertTypes TextureType;
public readonly ExportTypes TextureType;
public ExportKey(Texture src, ConvertTypes type)
public ExportKey(Texture src, ExportTypes type)
{
if (src == null)
{
@ -50,36 +56,13 @@ namespace VRMShaders
TextureType = type;
}
}
Dictionary<ExportKey, int> m_exportMap = new Dictionary<ExportKey, int>();
/// <summary>
/// Export する Texture2D のリスト。これが gltf.textures になる
/// </summary>
/// <typeparam name="Texture2D"></typeparam>
/// <returns></returns>
public readonly List<(Texture2D, ColorSpace)> Exported = new List<(Texture2D, ColorSpace)>();
/// <summary>
/// Texture の export index を得る
/// </summary>
/// <param name="src"></param>
/// <param name="textureType"></param>
/// <returns></returns>
public int GetTextureIndex(Texture src, ConvertTypes textureType)
{
if (src == null)
{
return -1;
}
return m_exportMap[new ExportKey(src, textureType)];
}
/// <summary>
/// sRGBなテクスチャーを処理し、index を確定させる
/// </summary>
/// <param name="src"></param>
/// <returns></returns>
public int ExportSRGB(Texture src)
public int ExportAsSRgb(Texture src)
{
if (src == null)
{
@ -87,13 +70,13 @@ namespace VRMShaders
}
// cache
if (m_exportMap.TryGetValue(new ExportKey(src, ConvertTypes.None), out var index))
if (m_exportMap.TryGetValue(new ExportKey(src, ExportTypes.Srgb), out var index))
{
return index;
}
// get Texture2D
index = Exported.Count;
index = m_exported.Count;
var texture2D = src as Texture2D;
if (m_textureSerializer.CanExportAsEditorAssetFile(texture2D))
{
@ -101,10 +84,10 @@ namespace VRMShaders
}
else
{
texture2D = TextureConverter.CopyTexture(src, TextureImportTypes.sRGB, null);
texture2D = TextureConverter.CopyTexture(src, ColorSpace.sRGB, null);
}
Exported.Add((texture2D, ColorSpace.sRGB));
m_exportMap.Add(new ExportKey(src, ConvertTypes.None), index);
m_exported.Add((texture2D, ColorSpace.sRGB));
m_exportMap.Add(new ExportKey(src, ExportTypes.Srgb), index);
return index;
}
@ -114,14 +97,14 @@ namespace VRMShaders
/// </summary>
/// <param name="src"></param>
/// <returns></returns>
public int ExportLinear(Texture src)
public int ExportAsLinear(Texture src)
{
if (src == null)
{
return -1;
}
var exportKey = new ExportKey(src, ConvertTypes.None);
var exportKey = new ExportKey(src, ExportTypes.Linear);
// search cache
if (m_exportMap.TryGetValue(exportKey, out var index))
@ -129,7 +112,7 @@ namespace VRMShaders
return index;
}
index = Exported.Count;
index = m_exported.Count;
var texture2d = src as Texture2D;
if (m_textureSerializer.CanExportAsEditorAssetFile(texture2d))
{
@ -137,9 +120,9 @@ namespace VRMShaders
}
else
{
texture2d = TextureConverter.CopyTexture(src, TextureImportTypes.Linear, null);
texture2d = TextureConverter.CopyTexture(src, ColorSpace.Linear, null);
}
Exported.Add((texture2d, ColorSpace.Linear));
m_exported.Add((texture2d, ColorSpace.Linear));
m_exportMap.Add(exportKey, index);
return index;
@ -152,7 +135,7 @@ namespace VRMShaders
/// <param name="smoothness"></param>
/// <param name="occlusionTexture"></param>
/// <returns></returns>
public int ExportMetallicSmoothnessOcclusion(Texture metallicSmoothTexture, float smoothness, Texture occlusionTexture)
public int ExportAsGltfMetallicSmoothnessOcclusionCombined(Texture metallicSmoothTexture, float smoothness, Texture occlusionTexture)
{
if (metallicSmoothTexture == null && occlusionTexture == null)
{
@ -160,11 +143,12 @@ namespace VRMShaders
}
// cache
if (metallicSmoothTexture != null && m_exportMap.TryGetValue(new ExportKey(metallicSmoothTexture, ConvertTypes.OcclusionMetallicRoughness), out var index))
// TODO 厳密なチェックをしていない
if (metallicSmoothTexture != null && m_exportMap.TryGetValue(new ExportKey(metallicSmoothTexture, ExportTypes.OcclusionMetallicRoughness), out var index))
{
return index;
}
if (occlusionTexture != null && m_exportMap.TryGetValue(new ExportKey(occlusionTexture, ConvertTypes.OcclusionMetallicRoughness), out index))
if (occlusionTexture != null && m_exportMap.TryGetValue(new ExportKey(occlusionTexture, ExportTypes.OcclusionMetallicRoughness), out index))
{
return index;
}
@ -172,17 +156,17 @@ namespace VRMShaders
//
// Unity と glTF で互換性が無いので必ず変換が必用
//
index = Exported.Count;
index = m_exported.Count;
var texture2D = OcclusionMetallicRoughnessConverter.Export(metallicSmoothTexture, smoothness, occlusionTexture);
Exported.Add((texture2D, ColorSpace.Linear));
m_exported.Add((texture2D, ColorSpace.Linear));
if (metallicSmoothTexture != null)
{
m_exportMap.Add(new ExportKey(metallicSmoothTexture, ConvertTypes.OcclusionMetallicRoughness), index);
m_exportMap.Add(new ExportKey(metallicSmoothTexture, ExportTypes.OcclusionMetallicRoughness), index);
}
if (occlusionTexture != null && occlusionTexture != metallicSmoothTexture)
{
m_exportMap.Add(new ExportKey(occlusionTexture, ConvertTypes.OcclusionMetallicRoughness), index);
m_exportMap.Add(new ExportKey(occlusionTexture, ExportTypes.OcclusionMetallicRoughness), index);
}
return index;
@ -193,7 +177,7 @@ namespace VRMShaders
/// </summary>
/// <param name="normalTexture"></param>
/// <returns></returns>
public int ExportNormal(Texture src)
public int ExportAsNormal(Texture src)
{
if (src == null)
{
@ -201,13 +185,13 @@ namespace VRMShaders
}
// cache
if (m_exportMap.TryGetValue(new ExportKey(src, ConvertTypes.Normal), out var index))
if (m_exportMap.TryGetValue(new ExportKey(src, ExportTypes.Normal), out var index))
{
return index;
}
// get Texture2D
index = Exported.Count;
index = m_exported.Count;
var texture2D = src as Texture2D;
if (m_textureSerializer.CanExportAsEditorAssetFile(texture2D))
{
@ -219,8 +203,8 @@ namespace VRMShaders
texture2D = NormalConverter.Export(src);
}
Exported.Add((texture2D, ColorSpace.Linear));
m_exportMap.Add(new ExportKey(src, ConvertTypes.Normal), index);
m_exported.Add((texture2D, ColorSpace.Linear));
m_exportMap.Add(new ExportKey(src, ExportTypes.Normal), index);
return index;
}

View File

@ -29,22 +29,4 @@ namespace VRMShaders
// TextureImporter.sRGBTexture = false;
Linear,
}
public static class TextureImportTypesExtensions
{
public static ColorSpace GetColorSpace(this TextureImportTypes textureType)
{
switch (textureType)
{
case TextureImportTypes.sRGB:
return ColorSpace.sRGB;
case TextureImportTypes.Linear:
case TextureImportTypes.StandardMap:
case TextureImportTypes.NormalMap:
return ColorSpace.Linear;
default:
throw new NotImplementedException();
}
}
}
}

View File

@ -99,18 +99,18 @@ namespace VRMShaders
{
var exporter = new TextureExporter(new EditorTextureSerializer());
Assert.AreEqual(-1, exporter.ExportMetallicSmoothnessOcclusion(null, 0, null));
Assert.AreEqual(-1, exporter.ExportAsGltfMetallicSmoothnessOcclusionCombined(null, 0, null));
}
{
var exporter = new TextureExporter(new EditorTextureSerializer());
Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(null, 0, occlusion));
Assert.AreEqual(1, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, null));
Assert.AreEqual(0, exporter.ExportAsGltfMetallicSmoothnessOcclusionCombined(null, 0, occlusion));
Assert.AreEqual(1, exporter.ExportAsGltfMetallicSmoothnessOcclusionCombined(metallic, 0, null));
}
{
var exporter = new TextureExporter(new EditorTextureSerializer());
Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, occlusion));
Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(null, 0, occlusion));
Assert.AreEqual(0, exporter.ExportMetallicSmoothnessOcclusion(metallic, 0, null));
Assert.AreEqual(0, exporter.ExportAsGltfMetallicSmoothnessOcclusionCombined(metallic, 0, occlusion));
Assert.AreEqual(0, exporter.ExportAsGltfMetallicSmoothnessOcclusionCombined(null, 0, occlusion));
Assert.AreEqual(0, exporter.ExportAsGltfMetallicSmoothnessOcclusionCombined(metallic, 0, null));
}
}
}