public virtual void Export(GltfExportSettings meshExportSettings, ITextureSerializer textureSerializer) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = glTF.AddBuffer(bytesBuffer); Nodes = Copy.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); var uniqueUnityMeshes = new MeshExportList(); uniqueUnityMeshes.GetInfo(Nodes, meshExportSettings); #region Materials and Textures Materials = uniqueUnityMeshes.GetUniqueMaterials().ToList(); m_textureExporter = new TextureExporter(textureSerializer); var materialExporter = CreateMaterialExporter(); glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureExporter, m_settings)).ToList(); #endregion #region Meshes MeshBlendShapeIndexMap = new Dictionary <Mesh, Dictionary <int, int> >(); foreach (var unityMesh in uniqueUnityMeshes) { var(gltfMesh, blendShapeIndexMap) = meshExportSettings.DivideVertexBuffer ? MeshExporter_DividedVertexBuffer.Export(glTF, bufferIndex, unityMesh, Materials, m_settings.InverseAxis.Create(), meshExportSettings) : MeshExporter_SharedVertexBuffer.Export(glTF, bufferIndex, unityMesh, Materials, m_settings.InverseAxis.Create(), meshExportSettings) ; glTF.meshes.Add(gltfMesh); Meshes.Add(unityMesh.Mesh); if (!MeshBlendShapeIndexMap.ContainsKey(unityMesh.Mesh)) { // 重複防止 MeshBlendShapeIndexMap.Add(unityMesh.Mesh, blendShapeIndexMap); } } #endregion #region Nodes and Skins var skins = uniqueUnityMeshes .SelectMany(x => x.Renderers) .Where(x => x.Item1 is SkinnedMeshRenderer && x.UniqueBones != null) .Select(x => x.Item1 as SkinnedMeshRenderer) .ToList() ; foreach (var node in Nodes) { var gltfNode = ExportNode(node, Nodes, uniqueUnityMeshes, skins); glTF.nodes.Add(gltfNode); } glTF.scenes = new List <gltfScene> { new gltfScene { nodes = Copy.transform.GetChildren().Select(x => Nodes.IndexOf(x)).ToArray(), } }; foreach (var x in uniqueUnityMeshes) { foreach (var(renderer, uniqueBones) in x.Renderers) { if (uniqueBones != null && renderer is SkinnedMeshRenderer smr) { var matrices = x.GetBindPoses().Select(m_settings.InverseAxis.Create().InvertMat4).ToArray(); var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var skin = new glTFSkin { inverseBindMatrices = accessor, joints = uniqueBones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(smr.rootBone), }; var skinIndex = glTF.skins.Count; glTF.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(renderer))) { var nodeIndex = Nodes.IndexOf(z); var node = glTF.nodes[nodeIndex]; node.skin = skinIndex; } } } } #endregion #if UNITY_EDITOR #region Animations var clips = new List <AnimationClip>(); var animator = Copy.GetComponent <Animator>(); var animation = Copy.GetComponent <Animation>(); if (animator != null) { clips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { clips = AnimationExporter.GetAnimationClips(animation); } if (clips.Any()) { foreach (AnimationClip clip in clips) { var animationWithCurve = AnimationExporter.Export(clip, Copy.transform, Nodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = glTF.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 1: outputAccessor.type = "SCALAR"; //outputAccessor.count = ; break; case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } animationWithCurve.Animation.name = clip.name; glTF.animations.Add(animationWithCurve.Animation); } } #endregion #endif ExportExtensions(textureSerializer); // Extension で Texture が増える場合があるので最後に呼ぶ var exported = m_textureExporter.Export(); for (var exportedTextureIdx = 0; exportedTextureIdx < exported.Count; ++exportedTextureIdx) { var(unityTexture, colorSpace) = exported[exportedTextureIdx]; glTF.PushGltfTexture(bufferIndex, unityTexture, colorSpace, textureSerializer); } FixName(glTF); }
public virtual void Export(MeshExportSettings meshExportSettings) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = glTF.AddBuffer(bytesBuffer); GameObject tmpParent = null; if (Copy.transform.childCount == 0) { tmpParent = new GameObject("tmpParent"); Copy.transform.SetParent(tmpParent.transform, true); Copy = tmpParent; } try { Nodes = Copy.transform.Traverse() .Skip(1) // exclude root object for the symmetry with the importer .ToList(); #region Materials and Textures Materials = Nodes.SelectMany(x => x.GetSharedMaterials()).Where(x => x != null).Distinct().ToList(); var unityTextures = Materials.SelectMany(x => TextureExporter.GetTextures(x)).Where(x => x.texture != null).Distinct().ToList(); TextureManager = new TextureExportManager(unityTextures.Select(x => x.texture)); var materialExporter = CreateMaterialExporter(); glTF.materials = Materials.Select(x => materialExporter.ExportMaterial(x, TextureManager)).ToList(); for (int i = 0; i < unityTextures.Count; ++i) { var unityTexture = unityTextures[i]; TextureExporter.ExportTexture(glTF, bufferIndex, TextureManager.GetExportTexture(i), unityTexture.textureType); } #endregion #region Meshes var unityMeshes = MeshWithRenderer.FromNodes(Nodes).ToList(); MeshBlendShapeIndexMap = new Dictionary <Mesh, Dictionary <int, int> >(); foreach (var(mesh, gltfMesh, blendShapeIndexMap) in MeshExporter.ExportMeshes( glTF, bufferIndex, unityMeshes, Materials, meshExportSettings)) { glTF.meshes.Add(gltfMesh); if (!MeshBlendShapeIndexMap.ContainsKey(mesh)) { // 同じmeshが複数回現れた MeshBlendShapeIndexMap.Add(mesh, blendShapeIndexMap); } } Meshes = unityMeshes.Select(x => x.Mesh).ToList(); #endregion #region Nodes and Skins var unitySkins = unityMeshes .Where(x => x.UniqueBones != null) .ToList(); glTF.nodes = Nodes.Select(x => ExportNode(x, Nodes, unityMeshes.Select(y => y.Renderer).ToList(), unitySkins.Select(y => y.Renderer as SkinnedMeshRenderer).ToList())).ToList(); glTF.scenes = new List <gltfScene> { new gltfScene { nodes = Copy.transform.GetChildren().Select(x => Nodes.IndexOf(x)).ToArray(), } }; foreach (var x in unitySkins) { var matrices = x.GetBindPoses().Select(y => y.ReverseZ()).ToArray(); var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var renderer = x.Renderer as SkinnedMeshRenderer; var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.UniqueBones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(renderer.rootBone), }; var skinIndex = glTF.skins.Count; glTF.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(x.Renderer))) { var nodeIndex = Nodes.IndexOf(z); var node = glTF.nodes[nodeIndex]; node.skin = skinIndex; } } #endregion #if UNITY_EDITOR #region Animations var clips = new List <AnimationClip>(); var animator = Copy.GetComponent <Animator>(); var animation = Copy.GetComponent <Animation>(); if (animator != null) { clips = AnimationExporter.GetAnimationClips(animator); } else if (animation != null) { clips = AnimationExporter.GetAnimationClips(animation); } if (clips.Any()) { foreach (AnimationClip clip in clips) { var animationWithCurve = AnimationExporter.Export(clip, Copy.transform, Nodes); foreach (var kv in animationWithCurve.SamplerMap) { var sampler = animationWithCurve.Animation.samplers[kv.Key]; var inputAccessorIndex = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Input); sampler.input = inputAccessorIndex; var outputAccessorIndex = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output); sampler.output = outputAccessorIndex; // modify accessors var outputAccessor = glTF.accessors[outputAccessorIndex]; var channel = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key); switch (glTFAnimationTarget.GetElementCount(channel.target.path)) { case 1: outputAccessor.type = "SCALAR"; //outputAccessor.count = ; break; case 3: outputAccessor.type = "VEC3"; outputAccessor.count /= 3; break; case 4: outputAccessor.type = "VEC4"; outputAccessor.count /= 4; break; default: throw new NotImplementedException(); } } animationWithCurve.Animation.name = clip.name; glTF.animations.Add(animationWithCurve.Animation); } } #endregion #endif } finally { if (tmpParent != null) { tmpParent.transform.GetChild(0).SetParent(null); if (Application.isPlaying) { GameObject.Destroy(tmpParent); } else { GameObject.DestroyImmediate(tmpParent); } } } }
/// <summary> /// Occlusion, Metallic, Roughness /// </summary> /// <param name="m"></param> /// <param name="textureManager"></param> /// <param name="material"></param> static void Export_OcclusionMetallicRoughness(Material m, TextureExporter textureManager, glTFMaterial material) { Texture metallicSmoothTexture = default; float smoothness = 1.0f; if (m.HasProperty("_MetallicGlossMap")) { if (m.HasProperty("_GlossMapScale")) { smoothness = m.GetFloat("_GlossMapScale"); } metallicSmoothTexture = m.GetTexture("_MetallicGlossMap"); } Texture occlusionTexture = default; var occlusionStrength = 1.0f; if (m.HasProperty("_OcclusionMap")) { occlusionTexture = m.GetTexture("_OcclusionMap"); if (occlusionTexture != null && m.HasProperty("_OcclusionStrength")) { occlusionStrength = m.GetFloat("_OcclusionStrength"); } } int index = textureManager.ExportMetallicSmoothnessOcclusion(metallicSmoothTexture, smoothness, occlusionTexture); if (index != -1 && metallicSmoothTexture != null) { material.pbrMetallicRoughness.metallicRoughnessTexture = new glTFMaterialMetallicRoughnessTextureInfo() { index = index, }; Export_MainTextureTransform(m, material.pbrMetallicRoughness.metallicRoughnessTexture); // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. material.pbrMetallicRoughness.metallicFactor = 1.0f; material.pbrMetallicRoughness.roughnessFactor = 1.0f; } else { if (m.HasProperty("_Metallic")) { material.pbrMetallicRoughness.metallicFactor = m.GetFloat("_Metallic"); } if (m.HasProperty("_Glossiness")) { material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_Glossiness"); } } if (index != -1 && occlusionTexture != null) { material.occlusionTexture = new glTFMaterialOcclusionTextureInfo() { index = index, strength = occlusionStrength, }; Export_MainTextureTransform(m, material.occlusionTexture); } }