using System; using System.Collections.Generic; using UniGLTF; using UniGLTF.Extensions.VRMC_materials_mtoon; using UniJSON; using UnityEngine; namespace UniVRM10 { /// /// Migration Target: VRM file with "VRM/UnlitTransparentZWrite" material exported with UniVRM v0.43 or lower. /// /// 過去の UniVRM の "VRM/UnlitTransparentZWrite" シェーダをマイグレーションする. /// 他の Unlit シェーダと違い、VRMC_materials_mtoon を用いてマイグレーションする. /// internal static class MigrationUnlitTransparentZWriteMaterial { private const int MaxRenderQueueOffset = 9; // NOTE: vrm-1.0 spec private const string Unity0XShaderName = "VRM/UnlitTransparentZWrite"; private const int Unity0XDefaultRenderQueue = 2501; public static bool Migrate(glTF gltf, IReadOnlyList vrm0XMaterials) { var anyMigrated = false; var mapper = GetRenderQueueMapper(vrm0XMaterials); for (var materialIdx = 0; materialIdx < gltf.materials.Count; ++materialIdx) { try { var newMaterial = Migrate(vrm0XMaterials[materialIdx], gltf.materials[materialIdx].name, mapper); if (newMaterial != null) { // NOTE: UnlitTransparentZWrite の場合は、名前を引き継いで、glTFMaterial を上書きする. gltf.materials[materialIdx] = newMaterial; anyMigrated = true; } } catch (Exception ex) { Debug.LogException(ex); } } return anyMigrated; } private static Dictionary GetRenderQueueMapper(IReadOnlyList vrm0XMaterials) { try { var renderQueueSet = new SortedSet(); foreach (var vrm0XMaterial in vrm0XMaterials) { var renderQueue = MigrationMaterialUtil.GetRenderQueue(vrm0XMaterial); if (renderQueue.HasValue && renderQueue.Value != -1) { renderQueueSet.Add(renderQueue.Value); } else { renderQueueSet.Add(Unity0XDefaultRenderQueue); } } var mapper = new Dictionary(); var currentQueueOffset = 0; foreach (var queue in renderQueueSet) { mapper.Add(queue, currentQueueOffset); currentQueueOffset = Mathf.Min(currentQueueOffset + 1, MaxRenderQueueOffset); } return mapper; } catch (Exception ex) { Debug.LogException(ex); return new Dictionary(); } } private static glTFMaterial Migrate(JsonNode vrm0XMaterial, string materialName, Dictionary renderQueueMapper) { try { if (MigrationMaterialUtil.GetShaderName(vrm0XMaterial) != Unity0XShaderName) { return null; } var baseColorFactor = MigrationMaterialUtil.GetBaseColorFactor(vrm0XMaterial); var baseColorTexture = MigrationMaterialUtil.GetBaseColorTexture(vrm0XMaterial); var emissiveTexture = new glTFMaterialEmissiveTextureInfo { index = baseColorTexture.index, extensions = baseColorTexture.extensions, }; var renderQueue = MigrationMaterialUtil.GetRenderQueue(vrm0XMaterial) ?? Unity0XDefaultRenderQueue; var renderQueueOffset = renderQueueMapper.ContainsKey(renderQueue) ? renderQueueMapper[renderQueue] : 0; var mtoonMaterial = new glTFMaterial { name = materialName, extensions = new glTFExtensionExport().Add( glTF_KHR_materials_unlit.ExtensionName, new ArraySegment(glTF_KHR_materials_unlit.Raw) ), pbrMetallicRoughness = new glTFPbrMetallicRoughness { baseColorFactor = new[] { 0f, 0f, 0f, baseColorFactor[3] }, // black + _Color.a baseColorTexture = baseColorTexture, // _MainTex metallicFactor = 0f, roughnessFactor = 1f, }, alphaMode = "BLEND", alphaCutoff = 0.5f, doubleSided = false, emissiveFactor = new[] { baseColorFactor[0], baseColorFactor[1], baseColorFactor[2] }, // _Color.rgb emissiveTexture = emissiveTexture, }; var mtoon10 = new VRMC_materials_mtoon { SpecVersion = Vrm10Exporter.MTOON_SPEC_VERSION, TransparentWithZWrite = true, // transparent with zWrite RenderQueueOffsetNumber = renderQueueOffset, ShadeColorFactor = new[] { 0f, 0f, 0f }, // black OutlineWidthMode = OutlineWidthMode.none // disable outline }; UniGLTF.Extensions.VRMC_materials_mtoon.GltfSerializer.SerializeTo(ref mtoonMaterial.extensions, mtoon10); return mtoonMaterial; } catch (Exception) { Debug.LogWarning($"Migration failed in VRM/UnlitTransparentZWrite material: {materialName}"); return null; } } } }