public void TextureTransformTest() { var tex0 = new Texture2D(128, 128) { wrapMode = TextureWrapMode.Repeat, filterMode = FilterMode.Bilinear, }; var textureManager = new TextureExportManager(new Texture[] { tex0 }); var srcMaterial = new Material(Shader.Find("Standard")); var offset = new Vector2(0.3f, 0.2f); var scale = new Vector2(0.5f, 0.6f); srcMaterial.mainTexture = tex0; srcMaterial.mainTextureOffset = offset; srcMaterial.mainTextureScale = scale; var materialExporter = new MaterialExporter(); 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); }
static void Export_Emission(Material m, TextureExportManager textureManager, glTFMaterial material) { if (m.IsKeywordEnabled("_EMISSION") == false) { return; } if (m.HasProperty("_EmissionColor")) { var color = m.GetColor("_EmissionColor"); if (color.maxColorComponent > 1) { color /= color.maxColorComponent; } material.emissiveFactor = new float[] { color.r, color.g, color.b }; } if (m.HasProperty("_EmissionMap")) { var index = textureManager.CopyAndGetIndex(m.GetTexture("_EmissionMap"), RenderTextureReadWrite.sRGB); if (index != -1) { material.emissiveTexture = new glTFMaterialEmissiveTextureInfo() { index = index, }; Export_MainTextureTransform(m, material.emissiveTexture); } } }
public void TextureExportTest() { // Dummy texture var tex0 = new Texture2D(128, 128) { wrapMode = TextureWrapMode.Clamp, filterMode = FilterMode.Trilinear, }; var textureManager = new TextureExportManager(new Texture[] { tex0 }); var material = new Material(Shader.Find("Standard")); material.mainTexture = tex0; var materialExporter = new MaterialExporter(); materialExporter.ExportMaterial(material, textureManager); var convTex0 = textureManager.GetExportTexture(0); var sampler = TextureSamplerUtil.Export(convTex0); Assert.AreEqual(glWrap.CLAMP_TO_EDGE, sampler.wrapS); Assert.AreEqual(glWrap.CLAMP_TO_EDGE, sampler.wrapT); Assert.AreEqual(glFilter.LINEAR_MIPMAP_LINEAR, sampler.minFilter); Assert.AreEqual(glFilter.LINEAR_MIPMAP_LINEAR, sampler.magFilter); }
static void Export_Metallic(Material m, TextureExportManager textureManager, glTFMaterial material) { int index = -1; if (m.HasProperty("_MetallicGlossMap")) { index = textureManager.ConvertAndGetIndex(m.GetTexture("_MetallicGlossMap"), new MetallicRoughnessConverter()); if (index != -1) { material.pbrMetallicRoughness.metallicRoughnessTexture = new glTFMaterialMetallicRoughnessTextureInfo() { index = index, }; } } if (index != -1 && m.HasProperty("_GlossMapScale")) { material.pbrMetallicRoughness.metallicFactor = 1.0f; material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_GlossMapScale"); } else { if (m.HasProperty("_Metallic")) { material.pbrMetallicRoughness.metallicFactor = m.GetFloat("_Metallic"); } if (m.HasProperty("_Glossiness")) { material.pbrMetallicRoughness.roughnessFactor = 1.0f - m.GetFloat("_Glossiness"); } } }
public void MaterialExportTest() { var material = new Material(Shader.Find("Standard")); material.SetColor("_EmissionColor", new Color(0, 1, 2, 1)); var materialExporter = new MaterialExporter(); var textureExportManager = new TextureExportManager(new Texture[] { }); var gltfMaterial = materialExporter.ExportMaterial(material, textureExportManager); Assert.AreEqual(gltfMaterial.emissiveFactor, new float[] { 0, 0.5f, 1 }); }
public virtual glTFMaterial ExportMaterial(Material m, TextureExportManager textureManager) { var material = CreateMaterial(m); // common params material.name = m.name; Export_Color(m, textureManager, material); Export_Metallic(m, textureManager, material); Export_Normal(m, textureManager, material); Export_Occlusion(m, textureManager, material); Export_Emission(m, textureManager, material); return(material); }
static void Export_Metallic(Material m, TextureExportManager textureManager, glTFMaterial material) { int index = -1; if (m.HasProperty("_MetallicGlossMap")) { float smoothness = 0.0f; if (m.HasProperty("_GlossMapScale")) { smoothness = m.GetFloat("_GlossMapScale"); } // Bake smoothness values into a texture. var converter = new MetallicRoughnessConverter(smoothness); index = textureManager.ConvertAndGetIndex(m.GetTexture("_MetallicGlossMap"), converter); if (index != -1) { material.pbrMetallicRoughness.metallicRoughnessTexture = new glTFMaterialMetallicRoughnessTextureInfo() { index = index, }; Export_MainTextureTransform(m, material.pbrMetallicRoughness.metallicRoughnessTexture); } } if (index != -1) { material.pbrMetallicRoughness.metallicFactor = 1.0f; // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212. 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"); } } }
static void Export_Color(Material m, TextureExportManager textureManager, glTFMaterial material) { if (m.HasProperty("_Color")) { material.pbrMetallicRoughness.baseColorFactor = m.color.ToArray(); } if (m.HasProperty("_MainTex")) { var index = textureManager.CopyAndGetIndex(m.GetTexture("_MainTex"), RenderTextureReadWrite.sRGB); if (index != -1) { material.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo() { index = index, }; } } }
static void Export_Occlusion(Material m, TextureExportManager textureManager, glTFMaterial material) { if (m.HasProperty("_OcclusionMap")) { var index = textureManager.ConvertAndGetIndex(m.GetTexture("_OcclusionMap"), new OcclusionConverter()); if (index != -1) { material.occlusionTexture = new glTFMaterialOcclusionTextureInfo() { index = index, }; } if (index != -1 && m.HasProperty("_OcclusionStrength")) { material.occlusionTexture.strength = m.GetFloat("_OcclusionStrength"); } } }
static void Export_Normal(Material m, TextureExportManager textureManager, glTFMaterial material) { if (m.HasProperty("_BumpMap")) { var index = textureManager.ConvertAndGetIndex(m.GetTexture("_BumpMap"), new NormalConverter()); if (index != -1) { material.normalTexture = new glTFMaterialNormalTextureInfo() { index = index, }; } if (index != -1 && m.HasProperty("_BumpScale")) { material.normalTexture.scale = m.GetFloat("_BumpScale"); } } }
static void Export_Emission(Material m, TextureExportManager textureManager, glTFMaterial material) { if (m.HasProperty("_EmissionColor")) { var color = m.GetColor("_EmissionColor"); material.emissiveFactor = new float[] { color.r, color.g, color.b }; } if (m.HasProperty("_EmissionMap")) { var index = textureManager.CopyAndGetIndex(m.GetTexture("_EmissionMap"), RenderTextureReadWrite.sRGB); if (index != -1) { material.emissiveTexture = new glTFMaterialEmissiveTextureInfo() { index = index, }; } } }
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 => TextureIO.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]; TextureIO.ExportTexture(glTF, bufferIndex, TextureManager.GetExportTexture(i), unityTexture.TextureType); } #endregion #region Meshes var unityMeshes = Nodes .Select(x => new MeshExporter.MeshWithRenderer { Mesh = x.GetSharedMesh(), Renderer = x.GetComponent <Renderer>(), }) .Where(x => { if (x.Mesh == null) { return(false); } if (x.Renderer.sharedMaterials == null || x.Renderer.sharedMaterials.Length == 0) { return(false); } return(true); }) .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 = Nodes .Select(x => x.GetComponent <SkinnedMeshRenderer>()).Where(x => x != null && x.bones != null && x.bones.Length > 0) .ToList(); glTF.nodes = Nodes.Select(x => ExportNode(x, Nodes, unityMeshes.Select(y => y.Renderer).ToList(), unitySkins)).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.sharedMesh.bindposes.Select(y => y.ReverseZ()).ToArray(); var accessor = glTF.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.bones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(x.rootBone), }; var skinIndex = glTF.skins.Count; glTF.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(x))) { 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); } } } }
public void ExportTest() { { var material = Resources.Load <Material>("Materials/pbr_opaque"); var exporter = new MaterialExporter(); var textures = GetTextures(material).ToList(); var exportManager = new TextureExportManager(textures); var exported = exporter.ExportMaterial(material, exportManager); Assert.True(exported.extensions == null || exported.extensions.KHR_materials_unlit == null); Assert.AreEqual("OPAQUE", exported.alphaMode); } { var material = Resources.Load <Material>("Materials/pbr_transparent"); var exporter = new MaterialExporter(); var textures = GetTextures(material).ToList(); var exportManager = new TextureExportManager(textures); var exported = exporter.ExportMaterial(material, exportManager); Assert.True(exported.extensions == null || exported.extensions.KHR_materials_unlit == null); Assert.AreEqual("BLEND", exported.alphaMode); } { var material = Resources.Load <Material>("Materials/pbr_cutout"); var exporter = new MaterialExporter(); var textures = GetTextures(material).ToList(); var exportManager = new TextureExportManager(textures); var exported = exporter.ExportMaterial(material, exportManager); Assert.True(exported.extensions == null || exported.extensions.KHR_materials_unlit == null); Assert.AreEqual("MASK", exported.alphaMode); } { var material = Resources.Load <Material>("Materials/unlit_color"); var exporter = new MaterialExporter(); var textures = GetTextures(material).ToList(); var exportManager = new TextureExportManager(textures); var exported = exporter.ExportMaterial(material, exportManager); Assert.NotNull(exported.extensions.KHR_materials_unlit); Assert.AreEqual("OPAQUE", exported.alphaMode); } { var material = Resources.Load <Material>("Materials/unlit_texture"); var exporter = new MaterialExporter(); var textures = GetTextures(material).ToList(); var exportManager = new TextureExportManager(textures); var exported = exporter.ExportMaterial(material, exportManager); Assert.NotNull(exported.extensions.KHR_materials_unlit); Assert.AreEqual("OPAQUE", exported.alphaMode); } { var material = Resources.Load <Material>("Materials/unlit_transparent"); var exporter = new MaterialExporter(); var textures = GetTextures(material).ToList(); var exportManager = new TextureExportManager(textures); var exported = exporter.ExportMaterial(material, exportManager); Assert.NotNull(exported.extensions.KHR_materials_unlit); Assert.AreEqual("BLEND", exported.alphaMode); } { var material = Resources.Load <Material>("Materials/unlit_cutout"); var exporter = new MaterialExporter(); var textures = GetTextures(material).ToList(); var exportManager = new TextureExportManager(textures); var exported = exporter.ExportMaterial(material, exportManager); Assert.NotNull(exported.extensions.KHR_materials_unlit); Assert.AreEqual("MASK", exported.alphaMode); } { // multimaterial var materials = new Material[] { Resources.Load <Material>("Materials/unlit_transparent"), Resources.Load <Material>("Materials/unlit_cutout") }; var exporter = new MaterialExporter(); var textures = materials.SelectMany(x => GetTextures(x)).ToList(); var exportManager = new TextureExportManager(textures); { var exported = exporter.ExportMaterial(materials[0], exportManager); Assert.NotNull(exported.extensions.KHR_materials_unlit); Assert.AreEqual("BLEND", exported.alphaMode); } { var exported = exporter.ExportMaterial(materials[1], exportManager); Assert.NotNull(exported.extensions.KHR_materials_unlit); Assert.AreEqual("MASK", exported.alphaMode); } } }
void FromGameObject(glTF gltf, GameObject go, bool useSparseAccessorForMorphTarget = false) { var bytesBuffer = new ArrayByteBuffer(new byte[50 * 1024 * 1024]); var bufferIndex = gltf.AddBuffer(bytesBuffer); GameObject tmpParent = null; if (go.transform.childCount == 0) { tmpParent = new GameObject("tmpParent"); go.transform.SetParent(tmpParent.transform, true); go = tmpParent; } try { Nodes = go.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 => TextureIO.GetTextures(x)).Where(x => x.Texture != null).Distinct().ToList(); /*List<TextureIO.TextureExportItem> unityTextures = new List<TextureIO.TextureExportItem>(); * for (int i = 0; i < Materials.Count; ++i) * { * var m = Materials[i]; * var props = ShaderPropExporter.PreShaderPropExporter.GetPropsForSupportedShader(m.shader.name); * if (props == null) * { * if (m.mainTexture != null) * unityTextures.Add(new TextureIO.TextureExportItem(m.mainTexture, glTFTextureTypes.BaseColor)); * } * else * { * foreach (var prop in props.Properties) * { * if (prop.ShaderPropertyType == ShaderPropExporter.ShaderPropertyType.TexEnv) * { * var tex = m.GetTexture(prop.Key); * if (tex != null) * unityTextures.Add(new TextureIO.TextureExportItem(tex, TextureIO.GetglTFTextureType(m.shader.name, prop.Key))); * } * } * } * }*/ 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]; TextureIO.ExportTexture(gltf, bufferIndex, TextureManager.GetExportTexture(i), unityTexture.TextureType); } #endregion #region Meshes var unityMeshes = Nodes .Select(x => new MeshWithRenderer { Mesh = x.GetSharedMesh(), Renderer = x.GetComponent <Renderer>(), }) .Where(x => { if (x.Mesh == null) { return(false); } if (x.Renderer.sharedMaterials == null || x.Renderer.sharedMaterials.Length == 0) { return(false); } return(true); }) .ToList(); MeshExporter.ExportMeshes(gltf, bufferIndex, unityMeshes, Materials, useSparseAccessorForMorphTarget, ExportOnlyBlendShapePosition); Meshes = unityMeshes.Select(x => x.Mesh).ToList(); #endregion #region Nodes and Skins var unitySkins = Nodes .Select(x => x.GetComponent <SkinnedMeshRenderer>()).Where(x => x != null && x.bones != null && x.bones.Length > 0) .ToList(); gltf.nodes = Nodes.Select(x => ExportNode(x, Nodes, unityMeshes.Select(y => y.Renderer).ToList(), unitySkins)).ToList(); gltf.scenes = new List <gltfScene> { new gltfScene { nodes = go.transform.GetChildren().Select(x => Nodes.IndexOf(x)).ToArray(), } }; foreach (var x in unitySkins) { var matrices = x.sharedMesh.bindposes.Select(y => y.ReverseZ()).ToArray(); var accessor = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, matrices, glBufferTarget.NONE); var skin = new glTFSkin { inverseBindMatrices = accessor, joints = x.bones.Select(y => Nodes.IndexOf(y)).ToArray(), skeleton = Nodes.IndexOf(x.rootBone), }; var skinIndex = gltf.skins.Count; gltf.skins.Add(skin); foreach (var z in Nodes.Where(y => y.Has(x))) { 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 = go.GetComponent <Animator>(); var animation = go.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, go.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); } } } }