MaterialImportParam

This commit is contained in:
ousttrue
2021-03-29 14:35:30 +09:00
parent 5fd98cc54c
commit 2c3ec107ec
24 changed files with 766 additions and 753 deletions

View File

@@ -36,6 +36,8 @@ namespace UniGLTF
MaterialFactory m_materialFactory;
public MaterialFactory MaterialFactory => m_materialFactory;
public readonly GltfMaterialImporter GltfMaterialImporter = new GltfMaterialImporter();
TextureFactory m_textureFactory;
public TextureFactory TextureFactory => m_textureFactory;
@@ -46,7 +48,7 @@ namespace UniGLTF
{
m_parser = parser;
m_textureFactory = new TextureFactory(externalObjectMap);
m_materialFactory = new MaterialFactory(m_parser, externalObjectMap);
m_materialFactory = new MaterialFactory(externalObjectMap);
}
#region Source
@@ -111,7 +113,7 @@ namespace UniGLTF
using (MeasureTime("LoadMaterials"))
{
await m_materialFactory.LoadMaterialsAsync(m_awaitCaller, m_textureFactory.GetTextureAsync);
await LoadMaterialsAsync();
}
var meshImporter = new MeshImporter();
@@ -171,6 +173,24 @@ namespace UniGLTF
await OnLoadModel(m_awaitCaller, MeasureTime);
}
public async Task LoadMaterialsAsync()
{
if (m_parser.GLTF.materials == null || m_parser.GLTF.materials.Count == 0)
{
// no material. work around.
var param = GltfMaterialImporter.CreateParam(m_parser, 0);
var material = await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync);
}
else
{
for (int i = 0; i < m_parser.GLTF.materials.Count; ++i)
{
var param = GltfMaterialImporter.CreateParam(m_parser, i);
var material = await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync);
}
}
}
protected virtual Task OnLoadModel(IAwaitCaller awaitCaller, Func<string, IDisposable> MeasureTime)
{
// do nothing

View File

@@ -0,0 +1,99 @@
using System.Collections.Generic;
using UnityEngine;
using VRMShaders;
namespace UniGLTF
{
public delegate bool TryCreateMaterialParamFromGltf(GltfParser parser, int i, out MaterialImportParam param);
public class GltfMaterialImporter
{
/// <summary>
/// gltfMaterialを解釈する関数。
/// 拡張するには、先頭に挿入するべし。
/// </summary>
/// <typeparam name="TryCreateMaterialParamFromGltf"></typeparam>
/// <returns></returns>
public readonly List<TryCreateMaterialParamFromGltf> GltfMaterialParamProcessors = new List<TryCreateMaterialParamFromGltf>();
public GltfMaterialImporter()
{
// unlit を試し
GltfMaterialParamProcessors.Add(GltfUnlitMaterial.TryCreateParam);
// PBR を作成する(失敗しない)
GltfMaterialParamProcessors.Add(GltfPBRMaterial.TryCreateParam);
}
public static string MaterialName(int index, glTFMaterial src)
{
if (src != null && !string.IsNullOrEmpty(src.name))
{
return src.name;
}
return $"material_{index:00}";
}
public MaterialImportParam CreateParam(GltfParser parser, int i)
{
foreach (var tryCreate in GltfMaterialParamProcessors)
{
if (tryCreate(parser, i, out MaterialImportParam param))
{
return param;
}
}
// fallback
#if VRM_DEVELOP
Debug.LogWarning($"material: {i} out of range. fallback");
#endif
return new MaterialImportParam(MaterialName(i, null), GltfPBRMaterial.ShaderName);
}
public static (Vector2, Vector2) GetTextureOffsetAndScale(glTFTextureInfo textureInfo)
{
Vector2 offset = new Vector2(0, 0);
Vector2 scale = new Vector2(1, 1);
if (glTF_KHR_texture_transform.TryGet(textureInfo, out glTF_KHR_texture_transform textureTransform))
{
if (textureTransform.offset != null && textureTransform.offset.Length == 2)
{
offset = new Vector2(textureTransform.offset[0], textureTransform.offset[1]);
}
if (textureTransform.scale != null && textureTransform.scale.Length == 2)
{
scale = new Vector2(textureTransform.scale[0], textureTransform.scale[1]);
}
offset.y = (offset.y + scale.y - 1.0f) * -1.0f;
}
return (offset, scale);
}
/// <summary>
/// for unittest
/// </summary>
public static glTF CreateMaterialForTest(glTFMaterial material)
{
return new glTF
{
materials = new System.Collections.Generic.List<glTFMaterial> {
material
},
textures = new List<glTFTexture>{
new glTFTexture{
name = "texture_0"
}
},
images = new List<glTFImage>{
new glTFImage{
name = "image_0",
mimeType = "image/png",
}
},
};
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 14bc3a4ce3e24924a9ae8bb1654a1b7b
guid: 06d7ddbd9b8b38544a74013a6992210b
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,213 @@
using System.Threading.Tasks;
using UnityEngine;
using VRMShaders;
namespace UniGLTF
{
/// <summary>
/// Gltf から MaterialImportParam に変換する
///
/// StandardShader variables
///
/// _Color
/// _MainTex
/// _Cutoff
/// _Glossiness
/// _Metallic
/// _MetallicGlossMap
/// _BumpScale
/// _BumpMap
/// _Parallax
/// _ParallaxMap
/// _OcclusionStrength
/// _OcclusionMap
/// _EmissionColor
/// _EmissionMap
/// _DetailMask
/// _DetailAlbedoMap
/// _DetailNormalMapScale
/// _DetailNormalMap
/// _UVSec
/// _EmissionScaleUI
/// _EmissionColorUI
/// _Mode
/// _SrcBlend
/// _DstBlend
/// _ZWrite
///
/// </summary>
public static class GltfPBRMaterial
{
public const string ShaderName = "Standard";
private enum BlendMode
{
Opaque,
Cutout,
Fade,
Transparent
}
public static TextureImportParam BaseColorTexture(GltfParser parser, glTFMaterial src)
{
var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture);
return GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale);
}
public static TextureImportParam StandardTexture(GltfParser parser, glTFMaterial src)
{
var metallicFactor = 1.0f;
var roughnessFactor = 1.0f;
if (src.pbrMetallicRoughness != null)
{
metallicFactor = src.pbrMetallicRoughness.metallicFactor;
roughnessFactor = src.pbrMetallicRoughness.roughnessFactor;
}
var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture);
return GltfTextureImporter.CreateStandard(parser,
src.pbrMetallicRoughness?.metallicRoughnessTexture?.index,
src.occlusionTexture?.index,
offset, scale,
metallicFactor,
roughnessFactor);
}
public static TextureImportParam NormalTexture(GltfParser parser, glTFMaterial src)
{
var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.normalTexture);
return GltfTextureImporter.CreateNormal(parser, src.normalTexture.index, offset, scale);
}
public static bool TryCreateParam(GltfParser parser, int i, out MaterialImportParam param)
{
if (i < 0 || i >= parser.GLTF.materials.Count)
{
param = default;
return false;
}
var src = parser.GLTF.materials[i];
param = new MaterialImportParam(GltfMaterialImporter.MaterialName(i, src), ShaderName);
var standardParam = default(TextureImportParam);
if (src.pbrMetallicRoughness != null || src.occlusionTexture != null)
{
if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null)
{
standardParam = StandardTexture(parser, src);
}
if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4)
{
var color = src.pbrMetallicRoughness.baseColorFactor;
param.Colors.Add("_Color", (new Color(color[0], color[1], color[2], color[3])).gamma);
}
if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1)
{
var textureParam = BaseColorTexture(parser, src);
param.TextureSlots.Add("_MainTex", textureParam);
}
if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1)
{
param.Actions.Add(material => material.EnableKeyword("_METALLICGLOSSMAP"));
param.TextureSlots.Add("_MetallicGlossMap", standardParam);
// Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212.
param.FloatValues.Add("_Metallic", 1.0f);
param.FloatValues.Add("_GlossMapScale", 1.0f);
}
else
{
param.FloatValues.Add("_Metallic", src.pbrMetallicRoughness.metallicFactor);
param.FloatValues.Add("_Glossiness", 1.0f - src.pbrMetallicRoughness.roughnessFactor);
}
}
if (src.normalTexture != null && src.normalTexture.index != -1)
{
param.Actions.Add(material => material.EnableKeyword("_NORMALMAP"));
var textureParam = NormalTexture(parser, src);
param.TextureSlots.Add("_BumpMap", textureParam);
param.FloatValues.Add("_BumpScale", src.normalTexture.scale);
}
if (src.occlusionTexture != null && src.occlusionTexture.index != -1)
{
param.TextureSlots.Add("_OcclusionMap", standardParam);
param.FloatValues.Add("_OcclusionStrength", src.occlusionTexture.strength);
}
if (src.emissiveFactor != null
|| (src.emissiveTexture != null && src.emissiveTexture.index != -1))
{
param.Actions.Add(material => {
material.EnableKeyword("_EMISSION");
material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
});
if (src.emissiveFactor != null && src.emissiveFactor.Length == 3)
{
param.Colors.Add("_EmissionColor", new Color(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]));
}
if (src.emissiveTexture != null && src.emissiveTexture.index != -1)
{
var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.emissiveTexture);
var textureParam = GltfTextureImporter.CreateSRGB(parser, src.emissiveTexture.index, offset, scale);
param.TextureSlots.Add("_EmissionMap", textureParam);
}
}
param.Actions.Add(material => {
BlendMode blendMode = BlendMode.Opaque;
// https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980
switch (src.alphaMode)
{
case "BLEND":
blendMode = BlendMode.Fade;
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 3000;
break;
case "MASK":
blendMode = BlendMode.Cutout;
material.SetOverrideTag("RenderType", "TransparentCutout");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.SetFloat("_Cutoff", src.alphaCutoff);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 2450;
break;
default: // OPAQUE
blendMode = BlendMode.Opaque;
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
break;
}
material.SetFloat("_Mode", (float)blendMode);
});
return true;
}
}
}

View File

@@ -42,7 +42,7 @@ namespace UniGLTF
// base color
if (m.pbrMetallicRoughness?.baseColorTexture != null)
{
yield return PBRMaterialItem.BaseColorTexture(parser, m);
yield return GltfPBRMaterial.BaseColorTexture(parser, m);
}
// metallic roughness
@@ -55,14 +55,14 @@ namespace UniGLTF
// emission
if (m.emissiveTexture != null)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(m.emissiveTexture);
var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(m.emissiveTexture);
yield return GltfTextureImporter.CreateSRGB(parser, m.emissiveTexture.index, offset, scale);
}
// normal
if (m.normalTexture != null)
{
yield return PBRMaterialItem.NormalTexture(parser, m);
yield return GltfPBRMaterial.NormalTexture(parser, m);
}
// occlusion
@@ -75,7 +75,7 @@ namespace UniGLTF
// metallicSmooth and occlusion
if (metallicRoughnessTexture.HasValue || occlusionTexture.HasValue)
{
yield return PBRMaterialItem.StandardTexture(parser, m);
yield return GltfPBRMaterial.StandardTexture(parser, m);
}
}

View File

@@ -0,0 +1,88 @@
using UnityEngine;
using VRMShaders;
namespace UniGLTF
{
public static class GltfUnlitMaterial
{
public const string ShaderName = "UniGLTF/UniUnlit";
public static bool TryCreateParam(GltfParser parser, int i, out MaterialImportParam param)
{
if (i < 0 || i >= parser.GLTF.materials.Count)
{
param = default;
return false;
}
var src = parser.GLTF.materials[i];
if (!glTF_KHR_materials_unlit.IsEnable(src))
{
param = default;
return false;
}
param = new MaterialImportParam(GltfMaterialImporter.MaterialName(i, src), ShaderName);
// texture
if (src.pbrMetallicRoughness.baseColorTexture != null)
{
var (offset, scale) = GltfMaterialImporter.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture);
var textureParam = GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale);
param.TextureSlots.Add("_MainTex", textureParam);
}
// color
if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4)
{
var color = src.pbrMetallicRoughness.baseColorFactor;
param.Colors.Add("_Color", (new Color(color[0], color[1], color[2], color[3])).gamma);
}
//renderMode
param.Actions.Add(material =>
{
if (src.alphaMode == "OPAQUE")
{
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque);
}
else if (src.alphaMode == "BLEND")
{
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Transparent);
}
else if (src.alphaMode == "MASK")
{
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Cutout);
material.SetFloat("_Cutoff", src.alphaCutoff);
}
else
{
// default OPAQUE
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque);
}
// culling
if (src.doubleSided)
{
UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Off);
}
else
{
UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Back);
}
// VColor
var hasVertexColor = parser.GLTF.MaterialHasVertexColor(i);
if (hasVertexColor)
{
UniUnlit.Utils.SetVColBlendMode(material, UniUnlit.UniUnlitVertexColorBlendOp.Multiply);
}
UniUnlit.Utils.ValidateProperties(material, true);
});
return true;
}
}
}

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: 77db57076c0650c469c3ff0d4853ce21
timeCreated: 1533624711
licenseType: Free
guid: f9748317ec6964a47b0a1c4150fe62e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

View File

@@ -1,246 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
namespace UniGLTF
{
public class MaterialFactory : IDisposable
{
GltfParser m_parser;
Dictionary<string, Material> m_externalMap;
public bool TryGetExternal(int index, out Material external)
{
if (m_externalMap != null)
{
var gltfMaterial = m_parser.GLTF.materials[index];
if (m_externalMap.TryGetValue(gltfMaterial.name, out external))
{
return true;
}
}
external = default;
return false;
}
public MaterialFactory(GltfParser parser, IEnumerable<(string, UnityEngine.Object)> externalMap)
{
m_parser = parser;
if (externalMap != null)
{
m_externalMap = externalMap
.Select(kv => (kv.Item1, kv.Item2 as Material))
.Where(kv => kv.Item2 != null)
.ToDictionary(kv => kv.Item1, kv => kv.Item2)
;
}
}
public delegate Task<Material> CreateMaterialAsyncFunc(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture);
CreateMaterialAsyncFunc m_createMaterialAsync;
public CreateMaterialAsyncFunc CreateMaterialAsync
{
set
{
m_createMaterialAsync = value;
}
get
{
if (m_createMaterialAsync == null)
{
m_createMaterialAsync = MaterialFactory.DefaultCreateMaterialAsync;
}
return m_createMaterialAsync;
}
}
public struct MaterialLoadInfo
{
public readonly Material Asset;
public readonly bool UseExternal;
public bool IsSubAsset => !UseExternal;
public MaterialLoadInfo(Material asset, bool useExternal)
{
Asset = asset;
UseExternal = useExternal;
}
}
List<MaterialLoadInfo> m_materials = new List<MaterialLoadInfo>();
public IReadOnlyList<MaterialLoadInfo> Materials => m_materials;
void Remove(Material material)
{
var index = m_materials.FindIndex(x => x.Asset == material);
if (index >= 0)
{
m_materials.RemoveAt(index);
}
}
public void Dispose()
{
foreach (var x in m_materials)
{
if (!x.UseExternal)
{
// 外部の '.asset' からロードしていない
#if VRM_DEVELOP
// Debug.Log($"Destroy {x.Asset}");
#endif
UnityEngine.Object.DestroyImmediate(x.Asset, false);
}
}
}
/// <summary>
/// 所有権(Dispose権)を移譲する
///
/// 所有権を移動する関数。
///
/// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる
/// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる
///
/// </summary>
/// <param name="take"></param>
public void TransferOwnership(Func<UnityEngine.Object, bool> take)
{
var list = new List<Material>();
foreach (var x in m_materials)
{
if (!x.UseExternal)
{
// 外部の '.asset' からロードしていない
if (take(x.Asset))
{
list.Add(x.Asset);
}
}
}
foreach (var x in list)
{
Remove(x);
}
}
public Material GetMaterial(int index)
{
if (index < 0) return null;
if (index >= m_materials.Count) return null;
return m_materials[index].Asset;
}
/// <summary>
/// テクスチャ生成
/// </summary>
/// <param name="getTexture"></param>
/// <returns></returns>
public async Task LoadMaterialsAsync(IAwaitCaller awaitCaller, GetTextureAsyncFunc getTexture)
{
if (m_parser.GLTF.materials == null || m_parser.GLTF.materials.Count == 0)
{
// no material. work around.
var material = await CreateMaterialAsync(awaitCaller, m_parser, 0, getTexture);
m_materials.Add(new MaterialLoadInfo(material, false));
return;
}
for (int i = 0; i < m_parser.GLTF.materials.Count; ++i)
{
if (TryGetExternal(i, out Material material))
{
m_materials.Add(new MaterialLoadInfo(material, true));
continue;
}
material = await CreateMaterialAsync(awaitCaller, m_parser, i, getTexture);
m_materials.Add(new MaterialLoadInfo(material, false));
}
}
public static string MaterialName(int index, glTFMaterial src)
{
if(src!=null && !string.IsNullOrEmpty(src.name))
{
return src.name;
}
return $"material_{index:00}";
}
public static (Vector2, Vector2) GetTextureOffsetAndScale(glTFTextureInfo textureInfo)
{
Vector2 offset = new Vector2(0, 0);
Vector2 scale = new Vector2(1, 1);
if (glTF_KHR_texture_transform.TryGet(textureInfo, out glTF_KHR_texture_transform textureTransform))
{
if (textureTransform.offset != null && textureTransform.offset.Length == 2)
{
offset = new Vector2(textureTransform.offset[0], textureTransform.offset[1]);
}
if (textureTransform.scale != null && textureTransform.scale.Length == 2)
{
scale = new Vector2(textureTransform.scale[0], textureTransform.scale[1]);
}
offset.y = (offset.y + scale.y - 1.0f) * -1.0f;
}
return (offset, scale);
}
public static void SetTextureOffsetAndScale(Material material, string propertyName, Vector2 offset, Vector2 scale)
{
material.SetTextureOffset(propertyName, offset);
material.SetTextureScale(propertyName, scale);
}
public static Task<Material> DefaultCreateMaterialAsync(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture)
{
if (i < 0 || i >= parser.GLTF.materials.Count)
{
UnityEngine.Debug.LogWarning("glTFMaterial is empty");
return PBRMaterialItem.CreateAsync(awaitCaller, parser, i, getTexture);
}
var x = parser.GLTF.materials[i];
if (glTF_KHR_materials_unlit.IsEnable(x))
{
var hasVertexColor = parser.GLTF.MaterialHasVertexColor(i);
return UnlitMaterialItem.CreateAsync(awaitCaller, parser, i, getTexture, hasVertexColor);
}
return PBRMaterialItem.CreateAsync(awaitCaller, parser, i, getTexture);
}
/// <summary>
/// for unittest
/// </summary>
/// <param name="i"></param>
/// <param name="material"></param>
/// <param name="getTexture"></param>
/// <returns></returns>
public static Material CreateMaterialForTest(int i, glTFMaterial material)
{
var gltf = new glTF
{
materials = new System.Collections.Generic.List<glTFMaterial> { material },
textures = new List<glTFTexture>{
new glTFTexture{
name = "texture_0"
}
},
images = new List<glTFImage>{
new glTFImage{
name = "image_0",
mimeType = "image/png",
}
},
};
var task = DefaultCreateMaterialAsync(default(ImmediateCaller), new GltfParser{GLTF = gltf}, i, null);
return task.Result;
}
}
}

View File

@@ -1,244 +0,0 @@

using System.Threading.Tasks;
using UnityEngine;
using VRMShaders;
namespace UniGLTF
{
/// StandardShader variables
///
/// _Color
/// _MainTex
/// _Cutoff
/// _Glossiness
/// _Metallic
/// _MetallicGlossMap
/// _BumpScale
/// _BumpMap
/// _Parallax
/// _ParallaxMap
/// _OcclusionStrength
/// _OcclusionMap
/// _EmissionColor
/// _EmissionMap
/// _DetailMask
/// _DetailAlbedoMap
/// _DetailNormalMapScale
/// _DetailNormalMap
/// _UVSec
/// _EmissionScaleUI
/// _EmissionColorUI
/// _Mode
/// _SrcBlend
/// _DstBlend
/// _ZWrite
public static class PBRMaterialItem
{
public const string ShaderName = "Standard";
private enum BlendMode
{
Opaque,
Cutout,
Fade,
Transparent
}
public static TextureImportParam BaseColorTexture(GltfParser parser, glTFMaterial src)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture);
return GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale);
}
public static TextureImportParam StandardTexture(GltfParser parser, glTFMaterial src)
{
var metallicFactor = 1.0f;
var roughnessFactor = 1.0f;
if (src.pbrMetallicRoughness != null)
{
metallicFactor = src.pbrMetallicRoughness.metallicFactor;
roughnessFactor = src.pbrMetallicRoughness.roughnessFactor;
}
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture);
return GltfTextureImporter.CreateStandard(parser,
src.pbrMetallicRoughness?.metallicRoughnessTexture?.index,
src.occlusionTexture?.index,
offset, scale,
metallicFactor,
roughnessFactor);
}
public static TextureImportParam NormalTexture(GltfParser parser, glTFMaterial src)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.normalTexture);
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 = (TextureImportParam _param) => Task.FromResult<Texture2D>(null);
}
var material = new Material(Shader.Find(ShaderName));
if (i < 0 || i >= parser.GLTF.materials.Count)
{
material.name = MaterialFactory.MaterialName(i, null);
return material;
}
var src = parser.GLTF.materials[i];
material.name = MaterialFactory.MaterialName(i, src);
var standardParam = default(TextureImportParam);
if (src.pbrMetallicRoughness != null || src.occlusionTexture != null)
{
if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null)
{
standardParam = StandardTexture(parser, src);
}
if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4)
{
var color = src.pbrMetallicRoughness.baseColorFactor;
material.color = (new Color(color[0], color[1], color[2], color[3])).gamma;
}
if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1)
{
var param = BaseColorTexture(parser, src);
material.mainTexture = await getTexture(param);
// Texture Offset and Scale
MaterialFactory.SetTextureOffsetAndScale(material, "_MainTex", param.Offset, param.Scale);
}
if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1)
{
material.EnableKeyword("_METALLICGLOSSMAP");
var texture = await getTexture(standardParam);
if (texture != null)
{
material.SetTexture(TextureImportParam.METALLIC_GLOSS_PROP, texture);
}
material.SetFloat("_Metallic", 1.0f);
// Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212.
material.SetFloat("_GlossMapScale", 1.0f);
// Texture Offset and Scale
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.metallicRoughnessTexture);
MaterialFactory.SetTextureOffsetAndScale(material, "_MetallicGlossMap", offset, scale);
}
else
{
material.SetFloat("_Metallic", src.pbrMetallicRoughness.metallicFactor);
material.SetFloat("_Glossiness", 1.0f - src.pbrMetallicRoughness.roughnessFactor);
}
}
if (src.normalTexture != null && src.normalTexture.index != -1)
{
material.EnableKeyword("_NORMALMAP");
var param = NormalTexture(parser, src);
var texture = await getTexture(param);
if (texture != null)
{
material.SetTexture(TextureImportParam.NORMAL_PROP, texture);
material.SetFloat("_BumpScale", src.normalTexture.scale);
}
// Texture Offset and Scale
MaterialFactory.SetTextureOffsetAndScale(material, "_BumpMap", param.Offset, param.Scale);
}
if (src.occlusionTexture != null && src.occlusionTexture.index != -1)
{
var texture = await getTexture(standardParam);
if (texture != null)
{
material.SetTexture(TextureImportParam.OCCLUSION_PROP, texture);
material.SetFloat("_OcclusionStrength", src.occlusionTexture.strength);
}
// Texture Offset and Scale
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.occlusionTexture);
MaterialFactory.SetTextureOffsetAndScale(material, "_OcclusionMap", offset, scale);
}
if (src.emissiveFactor != null
|| (src.emissiveTexture != null && src.emissiveTexture.index != -1))
{
material.EnableKeyword("_EMISSION");
material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
if (src.emissiveFactor != null && src.emissiveFactor.Length == 3)
{
material.SetColor("_EmissionColor", new Color(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]));
}
if (src.emissiveTexture != null && src.emissiveTexture.index != -1)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.emissiveTexture);
var param = GltfTextureImporter.CreateSRGB(parser, src.emissiveTexture.index, offset, scale);
var texture = await getTexture(param);
if (texture != null)
{
material.SetTexture("_EmissionMap", texture);
}
// Texture Offset and Scale
MaterialFactory.SetTextureOffsetAndScale(material, "_EmissionMap", param.Offset, param.Scale);
}
}
BlendMode blendMode = BlendMode.Opaque;
// https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980
switch (src.alphaMode)
{
case "BLEND":
blendMode = BlendMode.Fade;
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 3000;
break;
case "MASK":
blendMode = BlendMode.Cutout;
material.SetOverrideTag("RenderType", "TransparentCutout");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.SetFloat("_Cutoff", src.alphaCutoff);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 2450;
break;
default: // OPAQUE
blendMode = BlendMode.Opaque;
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
break;
}
material.SetFloat("_Mode", (float)blendMode);
return material;
}
}
}

View File

@@ -1,80 +0,0 @@

using System.Threading.Tasks;
using UnityEngine;
namespace UniGLTF
{
public static class UnlitMaterialItem
{
public const string ShaderName = "UniGLTF/UniUnlit";
public static async Task<Material> CreateAsync(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture, bool hasVertexColor)
{
if (getTexture == null)
{
getTexture = (_) => Task.FromResult<Texture2D>(default);
}
var src = parser.GLTF.materials[i];
var material = new Material(Shader.Find(ShaderName));
material.name = MaterialFactory.MaterialName(i, src);
// texture
if (src.pbrMetallicRoughness.baseColorTexture != null)
{
var (offset, scale) = MaterialFactory.GetTextureOffsetAndScale(src.pbrMetallicRoughness.baseColorTexture);
material.mainTexture = await getTexture(GltfTextureImporter.CreateSRGB(parser, src.pbrMetallicRoughness.baseColorTexture.index, offset, scale));
// Texture Offset and Scale
MaterialFactory.SetTextureOffsetAndScale(material, "_MainTex", offset, scale);
}
// color
if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4)
{
var color = src.pbrMetallicRoughness.baseColorFactor;
material.color = (new Color(color[0], color[1], color[2], color[3])).gamma;
}
//renderMode
if (src.alphaMode == "OPAQUE")
{
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque);
}
else if (src.alphaMode == "BLEND")
{
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Transparent);
}
else if (src.alphaMode == "MASK")
{
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Cutout);
material.SetFloat("_Cutoff", src.alphaCutoff);
}
else
{
// default OPAQUE
UniUnlit.Utils.SetRenderMode(material, UniUnlit.UniUnlitRenderMode.Opaque);
}
// culling
if (src.doubleSided)
{
UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Off);
}
else
{
UniUnlit.Utils.SetCullMode(material, UniUnlit.UniUnlitCullMode.Back);
}
// VColor
if (hasVertexColor)
{
UniUnlit.Utils.SetVColBlendMode(material, UniUnlit.UniUnlitVertexColorBlendOp.Multiply);
}
UniUnlit.Utils.ValidateProperties(material, true);
return material;
}
}
}

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using UnityEngine;
using VRMShaders;
namespace UniGLTF
{

View File

@@ -8,8 +8,6 @@ using VRMShaders;
namespace UniGLTF
{
public delegate Task<Texture2D> GetTextureAsyncFunc(TextureImportParam param);
/// <summary>
/// glTFTexture を TextureImportParam に変換する
/// </summary>

View File

@@ -2,6 +2,7 @@
using UnityEngine;
using UniJSON;
using System.Linq;
using VRMShaders;
namespace UniGLTF
{
@@ -31,12 +32,11 @@ namespace UniGLTF
var gltfMaterial = materialExporter.ExportMaterial(srcMaterial, textureManager);
gltfMaterial.pbrMetallicRoughness.baseColorTexture.extensions = gltfMaterial.pbrMetallicRoughness.baseColorTexture.extensions.Deserialize();
var dstMaterial = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual(dstMaterial.mainTextureOffset.x, offset.x, 0.3f);
Assert.AreEqual(dstMaterial.mainTextureOffset.y, offset.y, 0.2f);
Assert.AreEqual(dstMaterial.mainTextureScale.x, scale.x, 0.5f);
Assert.AreEqual(dstMaterial.mainTextureScale.y, scale.y, 0.6f);
Assert.IsTrue(glTF_KHR_texture_transform.TryGet(gltfMaterial.pbrMetallicRoughness.baseColorTexture, out glTF_KHR_texture_transform t));
Assert.AreEqual(t.offset[0], offset.x, 0.3f);
Assert.AreEqual(t.offset[1], offset.y, 0.2f);
Assert.AreEqual(t.scale[0], scale.x, 0.5f);
Assert.AreEqual(t.scale[1], scale.y, 0.6f);
}
[Test]
@@ -79,8 +79,7 @@ namespace UniGLTF
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
}
@@ -98,8 +97,7 @@ namespace UniGLTF
},
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
{
@@ -116,8 +114,7 @@ namespace UniGLTF
},
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
{
@@ -135,8 +132,7 @@ namespace UniGLTF
},
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
{
@@ -150,8 +146,7 @@ namespace UniGLTF
},
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
{
@@ -168,8 +163,7 @@ namespace UniGLTF
},
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
{
@@ -187,8 +181,7 @@ namespace UniGLTF
},
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
{
@@ -205,8 +198,7 @@ namespace UniGLTF
},
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
{
@@ -224,8 +216,7 @@ namespace UniGLTF
},
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
{
@@ -234,16 +225,14 @@ namespace UniGLTF
{
extensions = glTF_KHR_materials_unlit.Serialize().Deserialize(),
};
var material = MaterialFactory.CreateMaterialForTest(0, gltfMaterial);
Assert.AreEqual("UniGLTF/UniUnlit", material.shader.name);
Assert.IsTrue(glTF_KHR_materials_unlit.IsEnable(gltfMaterial));
}
}
[Test]
public void MaterialImportTest()
{
var material = MaterialFactory.CreateMaterialForTest(0, new glTFMaterial { });
Assert.AreEqual("Standard", material.shader.name);
Assert.IsFalse(glTF_KHR_materials_unlit.IsEnable(new glTFMaterial { }));
}
[Test]

View File

@@ -125,7 +125,7 @@ namespace VRM
//
// convert images(metallic roughness, occlusion map)
//
var task = m_context.MaterialFactory.LoadMaterialsAsync(default(ImmediateCaller), m_context.TextureFactory.GetTextureAsync);
var task = m_context.LoadMaterialsAsync();
if (!task.IsCompleted)
{
throw new Exception();

View File

@@ -0,0 +1,107 @@
using System.Collections.Generic;
using UniGLTF;
using UnityEngine;
using VRMShaders;
namespace VRM
{
public class MToonMaterialImporter
{
public static bool TryCreateParam(GltfParser parser, int i, glTF_VRM_Material vrmMaterial, out MaterialImportParam param)
{
if (vrmMaterial.shader == VRM.glTF_VRM_Material.VRM_USE_GLTFSHADER)
{
// fallback to gltf
param = default;
return false;
}
//
// restore VRM material
//
// use material.name, because material name may renamed in GltfParser.
var name = parser.GLTF.materials[i].name;
param = new MaterialImportParam(name, vrmMaterial.shader);
param.Actions.Add(material => material.renderQueue = vrmMaterial.renderQueue);
foreach (var kv in vrmMaterial.floatProperties)
{
param.FloatValues.Add(kv.Key, kv.Value);
}
var offsetScaleMap = new Dictionary<string, float[]>();
foreach (var kv in vrmMaterial.vectorProperties)
{
if (vrmMaterial.textureProperties.ContainsKey(kv.Key))
{
// texture offset & scale
offsetScaleMap.Add(kv.Key, kv.Value);
}
else
{
// vector4
var v = new Vector4(kv.Value[0], kv.Value[1], kv.Value[2], kv.Value[3]);
param.Vectors.Add(kv.Key, v);
}
}
foreach (var kv in vrmMaterial.textureProperties)
{
var (offset, scale) = (Vector2.zero, Vector2.one);
if (offsetScaleMap.TryGetValue(kv.Key, out float[] value))
{
offset = new Vector2(value[0], value[1]);
scale = new Vector2(value[2], value[3]);
}
var textureParam = MToonTextureParam.Create(parser, kv.Value, offset, scale, kv.Key, 1, 1);
param.TextureSlots.Add(kv.Key, textureParam);
}
foreach (var kv in vrmMaterial.keywordMap)
{
if (kv.Value)
{
param.Actions.Add(material => material.EnableKeyword(kv.Key));
}
else
{
param.Actions.Add(material => material.DisableKeyword(kv.Key));
}
}
foreach (var kv in vrmMaterial.tagMap)
{
param.Actions.Add(material => material.SetOverrideTag(kv.Key, kv.Value));
}
if (vrmMaterial.shader == MToon.Utils.ShaderName)
{
// TODO: Material拡張にMToonの項目が追加されたら旧バージョンのshaderPropから変換をかける
// インポート時にUniVRMに含まれるMToonのバージョンに上書きする
param.FloatValues[MToon.Utils.PropVersion] = MToon.Utils.VersionNumber;
}
return true;
}
List<glTF_VRM_Material> m_materials;
public MToonMaterialImporter(List<glTF_VRM_Material> materials)
{
m_materials = materials;
}
public bool TryCreateParam(GltfParser parser, int i, out MaterialImportParam param)
{
if (TryCreateParam(parser, i, m_materials[i], out param))
{
return true;
}
param = default;
return false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 35c90d5d3fa706b4f87a92ce4dc59008
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -26,7 +26,7 @@ namespace VRM
{
VRM = vrm;
// override material importer
MaterialFactory.CreateMaterialAsync = new VRMMaterialImporter(VRM.materialProperties).CreateMaterialAsync;
GltfMaterialImporter.GltfMaterialParamProcessors.Insert(0, new MToonMaterialImporter(VRM.materialProperties).TryCreateParam);
}
else
{

View File

@@ -1,139 +0,0 @@
using System.Collections.Generic;
using UniGLTF;
using UnityEngine;
using System.Linq;
using System;
using System.Threading.Tasks;
namespace VRM
{
public static class MToonMaterialItem
{
static string[] VRM_SHADER_NAMES =
{
"Standard",
"VRM/MToon",
"UniGLTF/UniUnlit",
"VRM/UnlitTexture",
"VRM/UnlitCutout",
"VRM/UnlitTransparent",
"VRM/UnlitTransparentZWrite",
};
public static async Task<Material> CreateAsync(IAwaitCaller awaitCaller, GltfParser parser, int m_index, glTF_VRM_Material vrmMaterial, GetTextureAsyncFunc getTexture)
{
var item = vrmMaterial;
var shaderName = item.shader;
var shader = Shader.Find(shaderName);
if (shader == null)
{
//
// no shader
//
if (VRM_SHADER_NAMES.Contains(shaderName))
{
Debug.LogErrorFormat("shader {0} not found. set Assets/VRM/Shaders/VRMShaders to Edit - project setting - Graphics - preloaded shaders", shaderName);
}
else
{
// #if VRM_DEVELOP
// Debug.LogWarningFormat("unknown shader {0}.", shaderName);
// #endif
}
return await MaterialFactory.DefaultCreateMaterialAsync(awaitCaller, parser, m_index, getTexture);
}
//
// restore VRM material
//
var material = new Material(shader);
// use material.name, because material name may renamed in GltfParser.
material.name = parser.GLTF.materials[m_index].name;
material.renderQueue = item.renderQueue;
foreach (var kv in item.floatProperties)
{
material.SetFloat(kv.Key, kv.Value);
}
var offsetScaleMap = new Dictionary<string, float[]>();
foreach (var kv in item.vectorProperties)
{
if (item.textureProperties.ContainsKey(kv.Key))
{
// texture offset & scale
offsetScaleMap.Add(kv.Key, kv.Value);
}
else
{
// vector4
var v = new Vector4(kv.Value[0], kv.Value[1], kv.Value[2], kv.Value[3]);
material.SetVector(kv.Key, v);
}
}
foreach (var kv in item.textureProperties)
{
var (offset, scale) = (Vector2.zero, Vector2.one);
if (offsetScaleMap.TryGetValue(kv.Key, out float[] value))
{
offset = new Vector2(value[0], value[1]);
scale = new Vector2(value[2], value[3]);
}
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);
MaterialFactory.SetTextureOffsetAndScale(material, kv.Key, offset, scale);
}
}
foreach (var kv in item.keywordMap)
{
if (kv.Value)
{
material.EnableKeyword(kv.Key);
}
else
{
material.DisableKeyword(kv.Key);
}
}
foreach (var kv in item.tagMap)
{
material.SetOverrideTag(kv.Key, kv.Value);
}
if (shaderName == MToon.Utils.ShaderName)
{
// TODO: Material拡張にMToonの項目が追加されたら旧バージョンのshaderPropから変換をかける
// インポート時にUniVRMに含まれるMToonのバージョンに上書きする
material.SetFloat(MToon.Utils.PropVersion, MToon.Utils.VersionNumber);
}
return material;
}
}
public class VRMMaterialImporter
{
List<glTF_VRM_Material> m_materials;
public VRMMaterialImporter(List<glTF_VRM_Material> materials)
{
m_materials = materials;
}
public Task<Material> CreateMaterialAsync(IAwaitCaller awaitCaller, GltfParser parser, int i, GetTextureAsyncFunc getTexture)
{
if (i == 0 && m_materials.Count == 0)
{
// dummy
return MaterialFactory.DefaultCreateMaterialAsync(awaitCaller, parser, i, getTexture);
}
return MToonMaterialItem.CreateAsync(awaitCaller, parser, i, m_materials[i], getTexture);
}
}
}

View File

@@ -29,7 +29,7 @@ namespace VRM
var vrmMaterial = VRMMaterialExporter.CreateFromMaterial(srcMaterial, textureManager);
Assert.AreEqual(vrmMaterial.vectorProperties["_MainTex"], new float[]{0.3f, 0.2f, 0.5f, 0.6f});
var materialImporter = new VRMMaterialImporter(new System.Collections.Generic.List<glTF_VRM_Material>{ vrmMaterial });
var materialImporter = new MToonMaterialImporter(new System.Collections.Generic.List<glTF_VRM_Material>{ vrmMaterial });
}
}
}

View File

@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
namespace VRMShaders
{
public delegate Task<Texture2D> GetTextureAsyncFunc(TextureImportParam param);
public class MaterialFactory : IDisposable
{
Dictionary<string, Material> m_externalMap;
public MaterialFactory(IEnumerable<(string, UnityEngine.Object)> externalMap)
{
if (externalMap == null)
{
externalMap = Enumerable.Empty<(string, UnityEngine.Object)>();
}
m_externalMap = externalMap
.Select(kv => (kv.Item1, kv.Item2 as Material))
.Where(kv => kv.Item2 != null)
.ToDictionary(kv => kv.Item1, kv => kv.Item2)
;
}
public struct MaterialLoadInfo
{
public readonly Material Asset;
public readonly bool UseExternal;
public bool IsSubAsset => !UseExternal;
public MaterialLoadInfo(Material asset, bool useExternal)
{
Asset = asset;
UseExternal = useExternal;
}
}
List<MaterialLoadInfo> m_materials = new List<MaterialLoadInfo>();
public IReadOnlyList<MaterialLoadInfo> Materials => m_materials;
void Remove(Material material)
{
var index = m_materials.FindIndex(x => x.Asset == material);
if (index >= 0)
{
m_materials.RemoveAt(index);
}
}
public void Dispose()
{
foreach (var x in m_materials)
{
if (!x.UseExternal)
{
// 外部の '.asset' からロードしていない
#if VRM_DEVELOP
// Debug.Log($"Destroy {x.Asset}");
#endif
UnityEngine.Object.DestroyImmediate(x.Asset, false);
}
}
}
/// <summary>
/// 所有権(Dispose権)を移譲する
///
/// 所有権を移動する関数。
///
/// * 所有権が移動する。return true => ImporterContext.Dispose の対象から外れる
/// * 所有権が移動しない。return false => Importer.Context.Dispose でDestroyされる
///
/// </summary>
/// <param name="take"></param>
public void TransferOwnership(Func<UnityEngine.Object, bool> take)
{
var list = new List<Material>();
foreach (var x in m_materials)
{
if (!x.UseExternal)
{
// 外部の '.asset' からロードしていない
if (take(x.Asset))
{
list.Add(x.Asset);
}
}
}
foreach (var x in list)
{
Remove(x);
}
}
public Material GetMaterial(int index)
{
if (index < 0) return null;
if (index >= m_materials.Count) return null;
return m_materials[index].Asset;
}
public async Task<Material> LoadAsync(MaterialImportParam param, GetTextureAsyncFunc getTexture)
{
if (m_externalMap.TryGetValue(param.Name, out Material material))
{
m_materials.Add(new MaterialLoadInfo(material, true));
return material;
}
if (getTexture == null)
{
getTexture = (_) => Task.FromResult<Texture2D>(null);
}
material = new Material(Shader.Find(param.ShaderName));
material.name = param.Name;
foreach(var kv in param.TextureSlots)
{
var texture = await getTexture(kv.Value);
if(texture!=null){
material.SetTexture(kv.Key, texture);
SetTextureOffsetAndScale(material, kv.Key, kv.Value.Offset, kv.Value.Scale);
}
}
foreach(var kv in param.Colors)
{
material.SetColor(kv.Key, kv.Value);
}
foreach(var kv in param.Vectors)
{
material.SetVector(kv.Key, kv.Value);
}
foreach(var kv in param.FloatValues)
{
material.SetFloat(kv.Key, kv.Value);
}
foreach(var action in param.Actions)
{
action(material);
}
m_materials.Add(new MaterialLoadInfo(material, false));
return material;
}
public static void SetTextureOffsetAndScale(Material material, string propertyName, Vector2 offset, Vector2 scale)
{
material.SetTextureOffset(propertyName, offset);
material.SetTextureScale(propertyName, scale);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace VRMShaders
{
public class MaterialImportParam
{
public readonly string Name;
public readonly string ShaderName;
public readonly Dictionary<string, TextureImportParam> TextureSlots = new Dictionary<string, TextureImportParam>();
public readonly Dictionary<string, float> FloatValues = new Dictionary<string, float>();
public readonly Dictionary<string, Color> Colors = new Dictionary<string, Color>();
public readonly Dictionary<string, Vector4> Vectors = new Dictionary<string, Vector4>();
public readonly List<Action<Material>> Actions = new List<Action<Material>>();
public MaterialImportParam(string name, string shaderName)
{
Name = name;
ShaderName = shaderName;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0844821341efaf644b91bff72f813a2c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: