public async void Setup(SyncObject obj) { // TODO: dynamic model change handling if (!obj.HasField("model") || !(obj.GetField("model") is BlobHandle)) { // TODO: obj.WriteErrorLog("Model", $"This object has no model field or not a blob handle. Ignoring."); return; } BlobHandle handle = (BlobHandle)obj.GetField("model"); Blob blob = await obj.Node.ReadBlob(handle); obj.WriteDebugLog("Model", $"Blob {handle} loaded"); // Because UniGLTF.ImporterContext is the parent class of VRMImporterContext, // ( https://github.com/vrm-c/UniVRM/blob/3b68eb7f99bfe78ea9c83ea75511282ef1782f1a/Assets/VRM/UniVRM/Scripts/Format/VRMImporterContext.cs#L11 ) // loading procedure is probably almost same (See PlyayerAvatar.cs for VRM loading). // https://github.com/vrm-c/UniVRM/blob/3b68eb7f99bfe78ea9c83ea75511282ef1782f1a/Assets/VRM/UniGLTF/Editor/Tests/UniGLTFTests.cs#L46 ctx = new UniGLTF.ImporterContext(); // ParseGlb parses GLB file. // https://github.com/vrm-c/UniVRM/blob/3b68eb7f99bfe78ea9c83ea75511282ef1782f1a/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs#L239 // Currently, only GLB (glTF binary format) is supported because it is self-contained ctx.ParseGlb(blob.Data); ctx.Root = gameObject; await ctx.LoadAsyncTask(); // UniGLTF also has ShowMeshes https://github.com/ousttrue/UniGLTF/wiki/Rutime-API#import ctx.ShowMeshes(); obj.WriteDebugLog("Model", "Model load completed"); LoadComplete?.Invoke(this); }
async void LoadModelAsync(string path, bool isVrm) { if (!File.Exists(path)) { return; } Debug.LogFormat("{0}", path); GltfData data; try { data = new AutoGltfFileParser(path).Parse(); } catch (Exception ex) { Debug.LogWarningFormat("parse error: {0}", ex); return; } if (isVrm) { try { var vrm = new VRMData(data); using (var loader = new VRMImporterContext(vrm, materialGenerator: GetVrmMaterialGenerator(m_useUrpMaterial.isOn, vrm.VrmExtension))) { await m_texts.UpdateMetaAsync(loader); var instance = await loader.LoadAsync(GetIAwaitCaller(m_useAsync.isOn)); SetModel(instance); } } catch (NotVrm0Exception) { // retry Debug.LogWarning("file extension is vrm. but not vrm ?"); using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: GetGltfMaterialGenerator(m_useUrpMaterial.isOn))) { var instance = await loader.LoadAsync(GetIAwaitCaller(m_useAsync.isOn)); SetModel(instance); } } } else { using (var loader = new UniGLTF.ImporterContext(data, materialGenerator: GetGltfMaterialGenerator(m_useUrpMaterial.isOn))) { var instance = await loader.LoadAsync(GetIAwaitCaller(m_useAsync.isOn)); SetModel(instance); } } }
public static async Task <RuntimeGltfInstance> LoadAsync(string path, IAwaitCaller awaitCaller = null, MaterialGeneratorCallback materialGeneratorCallback = null, MetaCallback metaCallback = null, bool loadAnimation = false ) { if (!File.Exists(path)) { throw new FileNotFoundException(path); } if (awaitCaller == null) { Debug.LogWarning("VrmUtility.LoadAsync: awaitCaller argument is null. ImmediateCaller is used as the default fallback. When playing, we recommend RuntimeOnlyAwaitCaller."); awaitCaller = new ImmediateCaller(); } using (GltfData data = new AutoGltfFileParser(path).Parse()) { try { var vrm = new VRMData(data); IMaterialDescriptorGenerator materialGen = default; if (materialGeneratorCallback != null) { materialGen = materialGeneratorCallback(vrm.VrmExtension); } using (var loader = new VRMImporterContext(vrm, materialGenerator: materialGen, loadAnimation: loadAnimation)) { if (metaCallback != null) { var meta = await loader.ReadMetaAsync(awaitCaller, true); metaCallback(meta); } return(await loader.LoadAsync(awaitCaller)); } } catch (NotVrm0Exception) { // retry Debug.LogWarning("file extension is vrm. but not vrm ?"); using (var loader = new UniGLTF.ImporterContext(data)) { return(await loader.LoadAsync(awaitCaller)); } } } }
public static void ImportAsset(string src, string ext, UnityPath prefabPath) { if (!prefabPath.IsUnderAssetsFolder) { Debug.LogWarningFormat("out of asset path: {0}", prefabPath); return; } var context = new ImporterContext(); context.Parse(src); // Extract textures to assets folder context.ExtranctImages(prefabPath); ImportDelayed(src, prefabPath, context); }
public static void ImportAnimation(ImporterContext ctx) { // animation if (ctx.GLTF.animations != null && ctx.GLTF.animations.Any()) { var animation = ctx.Root.AddComponent <Animation>(); ctx.AnimationClips = ImportAnimationClip(ctx); foreach (var clip in ctx.AnimationClips) { animation.AddClip(clip, clip.name); } if (ctx.AnimationClips.Count > 0) { animation.clip = ctx.AnimationClips.First(); } } }
/// <summary> /// glb をパースして、UnityObject化、さらにAsset化する /// </summary> /// <param name="scriptedImporter"></param> /// <param name="context"></param> /// <param name="reverseAxis"></param> protected static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, Axes reverseAxis, RenderPipelineTypes renderPipeline) { #if VRM_DEVELOP Debug.Log("OnImportAsset to " + scriptedImporter.assetPath); #endif // // Parse(parse glb, parser gltf json) // var data = new AutoGltfFileParser(scriptedImporter.assetPath).Parse(); // // Import(create unity objects) // // 2 回目以降の Asset Import において、 Importer の設定で Extract した UnityEngine.Object が入る var extractedObjects = scriptedImporter.GetExternalObjectMap() .Where(x => x.Value != null) .ToDictionary(kv => new SubAssetKey(kv.Value.GetType(), kv.Key.name), kv => kv.Value); IMaterialDescriptorGenerator materialGenerator = GetMaterialGenerator(renderPipeline); using (var loader = new ImporterContext(data, extractedObjects, materialGenerator: materialGenerator)) { // Configure TextureImporter to Extracted Textures. foreach (var textureInfo in loader.TextureDescriptorGenerator.Get().GetEnumerable()) { TextureImporterConfigurator.Configure(textureInfo, loader.TextureFactory.ExternalTextures); } loader.InvertAxis = reverseAxis; var loaded = loader.Load(); loaded.ShowMeshes(); loaded.TransferOwnership((k, o) => { context.AddObjectToAsset(k.Name, o); }); var root = loaded.Root; GameObject.DestroyImmediate(loaded); context.AddObjectToAsset(root.name, root); context.SetMainObject(root); } }
/// <summary> /// Build unity objects from parsed gltf /// </summary> public static void Load(this ImporterContext self) { var meassureTime = new ImporterContextSpeedLog(); var task = self.LoadAsync(default(ImmediateCaller), meassureTime.MeasureTime); if (!task.IsCompleted) { throw new Exception(); } if (task.IsFaulted) { throw new AggregateException(task.Exception); } #if VRM_DEVELOP Debug.Log($"{self.Parser.TargetPath}: {meassureTime.GetSpeedLog()}"); #endif }
public void Import(ImporterContext context) { // animation if (context.GLTF.animations != null && context.GLTF.animations.Any()) { var animation = context.Root.AddComponent <Animation>(); context.AnimationClips = ImportAnimationClips(context.GLTF, context.InvertAxis); foreach (var clip in context.AnimationClips) { animation.AddClip(clip, clip.name); } if (context.AnimationClips.Count > 0) { animation.clip = context.AnimationClips.First(); } } }
static void ImportAnimation(ImporterContext ctx) { // animation if (ctx.GLTF.animations != null && ctx.GLTF.animations.Any()) { ctx.Animation = new AnimationClip(); ctx.Animation.name = ANIMATION_NAME; ctx.Animation.ClearCurves(); ImportAnimation(ctx, ctx.Animation); ctx.Animation.legacy = true; ctx.Animation.name = "legacy"; ctx.Animation.wrapMode = WrapMode.Loop; var animation = ctx.Root.AddComponent <Animation>(); animation.clip = ctx.Animation; } }
/// <summary> /// glb をパースして、UnityObject化、さらにAsset化する /// </summary> /// <param name="scriptedImporter"></param> /// <param name="context"></param> /// <param name="reverseAxis"></param> public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, Axises reverseAxis) { #if VRM_DEVELOP Debug.Log("OnImportAsset to " + scriptedImporter.assetPath); #endif // // Parse(parse glb, parser gltf json) // var parser = new GltfParser(); parser.ParsePath(scriptedImporter.assetPath); // // Import(create unity objects) // var externalObjectMap = scriptedImporter.GetExternalObjectMap().Select(kv => (kv.Value.name, kv.Value)).ToArray(); var externalTextures = EnumerateTexturesFromUri(externalObjectMap, parser, UnityPath.FromUnityPath(scriptedImporter.assetPath).Parent).ToArray(); using (var loader = new ImporterContext(parser, externalObjectMap.Concat(externalTextures))) { // settings TextureImporters foreach (var(key, textureInfo) in GltfTextureEnumerator.EnumerateAllTexturesDistinct(parser)) { TextureImporterConfigurator.Configure(textureInfo, loader.TextureFactory.ExternalMap); } loader.InvertAxis = reverseAxis; loader.Load(); loader.ShowMeshes(); loader.TransferOwnership(o => { context.AddObjectToAsset(o.name, o); if (o is GameObject) { // Root GameObject is main object context.SetMainObject(loader.Root); } return(true); }); } }
public static void SetupSkinning(ImporterContext context, List<TransformWithSkin> nodes, int i) { var x = nodes[i]; var skinnedMeshRenderer = x.Transform.GetComponent<SkinnedMeshRenderer>(); if (skinnedMeshRenderer != null) { var mesh = skinnedMeshRenderer.sharedMesh; if (x.SkinIndex.HasValue) { if (mesh == null) throw new Exception(); if (skinnedMeshRenderer == null) throw new Exception(); if (x.SkinIndex.Value < context.GLTF.skins.Count) { var skin = context.GLTF.skins[x.SkinIndex.Value]; skinnedMeshRenderer.sharedMesh = null; var joints = skin.joints.Select(y => nodes[y].Transform).ToArray(); skinnedMeshRenderer.bones = joints; //skinnedMeshRenderer.rootBone = nodes[skin.skeleton].Transform; if (skin.inverseBindMatrices != -1) { // BlendShape only ? #if false // https://docs.unity3d.com/ScriptReference/Mesh-bindposes.html var hipsParent = nodes[0].Transform; var calculatedBindPoses = joints.Select(y => y.worldToLocalMatrix * hipsParent.localToWorldMatrix).ToArray(); mesh.bindposes = calculatedBindPoses; #else var bindPoses = context.GLTF.GetArrayFromAccessor<Matrix4x4>(skin.inverseBindMatrices) .Select(y => y.ReverseZ()) .ToArray() ; mesh.bindposes = bindPoses; #endif } skinnedMeshRenderer.sharedMesh = mesh; } } } }
public static async Task <RuntimeGltfInstance> LoadAsync(string path, IAwaitCaller awaitCaller = null, MaterialGeneratorCallback materialGeneratorCallback = null, MetaCallback metaCallback = null ) { if (!File.Exists(path)) { throw new FileNotFoundException(path); } using (GltfData data = new AutoGltfFileParser(path).Parse()) { try { var vrm = new VRMData(data); IMaterialDescriptorGenerator materialGen = default; if (materialGeneratorCallback != null) { materialGen = materialGeneratorCallback(vrm.VrmExtension); } using (var loader = new VRMImporterContext(vrm, materialGenerator: materialGen)) { if (metaCallback != null) { var meta = await loader.ReadMetaAsync(new ImmediateCaller(), true); metaCallback(meta); } return(await loader.LoadAsync(awaitCaller)); } } catch (NotVrm0Exception) { // retry Debug.LogWarning("file extension is vrm. but not vrm ?"); using (var loader = new UniGLTF.ImporterContext(data)) { return(await loader.LoadAsync(awaitCaller)); } } } }
static ImporterContext ImportGltf(string srcPath, bool isGlb) { Debug.LogFormat("ImportGltf: {0}", srcPath); var context = new ImporterContext { Path = srcPath, }; if (isGlb) { glbImporter.Import <glTF>(context, File.ReadAllBytes(srcPath)); } else { context.Json = File.ReadAllText(srcPath, System.Text.Encoding.UTF8); gltfImporter.Import <glTF>(context, new ArraySegment <byte>()); } return(context); }
GameObject Load(string path) { var bytes = File.ReadAllBytes(path); Debug.LogFormat("[OnClick] {0}", path); var context = new ImporterContext(); var ext = Path.GetExtension(path).ToLower(); switch (ext) { case ".gltf": context.ParseJson(Encoding.UTF8.GetString(bytes), new FileSystemStorage(Path.GetDirectoryName(path))); break; case ".zip": { var zipArchive = Zip.ZipArchiveStorage.Parse(bytes); var gltf = zipArchive.Entries.FirstOrDefault(x => x.FileName.ToLower().EndsWith(".gltf")); if (gltf == null) { throw new Exception("no gltf in archive"); } var jsonBytes = zipArchive.Extract(gltf); var json = Encoding.UTF8.GetString(jsonBytes); context.ParseJson(json, zipArchive); } break; case ".glb": context.ParseGlb(bytes); break; default: throw new NotImplementedException(); } context.Load(); context.Root.name = Path.GetFileNameWithoutExtension(path); context.ShowMeshes(); return(context.Root); }
public void UniGLTFSimpleSceneTest() { var go = CreateSimpleScene(); ImporterContext context = default; try { // export var gltf = new glTF(); string json = null; using (var exporter = new gltfExporter(gltf)) { exporter.Prepare(go); exporter.Export(MeshExportSettings.Default); // remove empty buffer gltf.buffers.Clear(); json = gltf.ToJson(); } // parse var parser = new GltfParser(); parser.ParseJson(json, new SimpleStorage(new ArraySegment <byte>())); // import context = new ImporterContext(parser); context.Load(); AssertAreEqual(go.transform, context.Root.transform); } finally { //Debug.LogFormat("Destroy, {0}", go.name); GameObject.DestroyImmediate(go); if (context != null) { var editor = new EditorImporterContext(context); editor.EditorDestroyRootAndAssets(); } } }
public static void ImportMenu() { var path = EditorUtility.OpenFilePanel("open gltf", "", "gltf,glb"); if (string.IsNullOrEmpty(path)) { return; } if (Application.isPlaying) { // // load into scene // var parser = new GltfParser(); parser.ParsePath(path); var context = new ImporterContext(parser); context.Load(); context.ShowMeshes(); Selection.activeGameObject = context.Root; } else { // // save as asset // if (path.StartsWithUnityAssetPath()) { Debug.LogWarningFormat("disallow import from folder under the Assets"); return; } var assetPath = EditorUtility.SaveFilePanel("save prefab", "Assets", Path.GetFileNameWithoutExtension(path), "prefab"); if (string.IsNullOrEmpty(path)) { return; } // import as asset gltfAssetPostprocessor.ImportAsset(path, Path.GetExtension(path).ToLower(), UnityPath.FromFullpath(assetPath)); } }
/// <summary> /// Build unity objects from parsed gltf /// </summary> public static RuntimeGltfInstance Load(this ImporterContext self) { var meassureTime = new ImporterContextSpeedLog(); var task = self.LoadAsync(new ImmediateCaller(), meassureTime.MeasureTime); if (!task.IsCompleted) { throw new Exception(); } if (task.IsFaulted) { throw new AggregateException(task.Exception); } #if VRM_DEVELOP Debug.Log($"{self.Data.TargetPath}: {meassureTime.GetSpeedLog()}"); #endif return(task.Result); }
/// <summary> /// Build unity objects from parsed gltf /// </summary> public static void Load(this ImporterContext self) { var meassureTime = new ImporterContextSpeedLog(); var task = self.LoadAsync(default(ImmediateCaller), meassureTime.MeasureTime); if (!task.IsCompleted) { throw new Exception(); } if (task.IsFaulted) { if (task.Exception is AggregateException ae && ae.InnerExceptions.Count == 1) { throw ae.InnerException; } else { throw task.Exception; } }
/// <summary> /// Build unity objects from parsed gltf /// </summary> public static void Load(this ImporterContext self) { var meassureTime = new ImporterContextSpeedLog(); using (var queue = TaskQueue.Create()) { var task = self.LoadAsync(meassureTime.MeasureTime); // 中断された await を消化する while (!task.IsCompleted) { // execute synchronous queue.ExecuteOneCallback(); } } #if VRM_DEVELOP Debug.Log(meassureTime.GetSpeedLog()); #endif }
static void RuntimeLoadExport(FileInfo gltf, int subStrStart) { var parser = new GltfParser(); try { parser.ParsePath(gltf.FullName); } catch (Exception ex) { Debug.LogError($"ParseError: {gltf}"); Debug.LogException(ex); } using (var loader = new ImporterContext(parser)) { try { loader.Load(); } catch (Exception ex) { Message(gltf.FullName.Substring(subStrStart), ex); } if (Skip.Contains(gltf.Directory.Parent.Name)) { // Export issue: // skip return; } if (loader.Root == null) { Debug.LogWarning($"root is null: ${gltf}"); return; } Export(loader.Root); } }
public static void ImportMenu() { var path = UnityEditor.EditorUtility.OpenFilePanel("open gltf", "", "gltf,glb"); if (!string.IsNullOrEmpty(path)) { Debug.Log(path); var context = new ImporterContext { Path = path, }; var bytes = File.ReadAllBytes(path); var ext = Path.GetExtension(path).ToLower(); switch (ext) { case ".gltf": { context.ParseJson <glTF>(Encoding.UTF8.GetString(bytes), new FileSystemStorage(Path.GetDirectoryName(path))); gltfImporter.Import <glTF>(context); context.Root.name = Path.GetFileNameWithoutExtension(path); context.ShowMeshes(); Selection.activeGameObject = context.Root; } break; case ".glb": { context.ParseGlb <glTF>(bytes); gltfImporter.Import <glTF>(context); context.Root.name = Path.GetFileNameWithoutExtension(path); context.ShowMeshes(); Selection.activeGameObject = context.Root; } break; default: Debug.LogWarningFormat("unknown ext: {0}", path); break; } } }
static void RuntimeLoadExport(FileInfo gltf, int subStrStart) { GltfData data = null; try { data = new AutoGltfFileParser(gltf.FullName).Parse(); } catch (Exception ex) { Debug.LogError($"ParseError: {gltf}"); Debug.LogException(ex); } using (data) using (var loader = new ImporterContext(data)) { try { var loaded = loader.Load(); if (loaded == null) { Debug.LogWarning($"root is null: ${gltf}"); return; } if (Skip.Contains(gltf.Directory.Parent.Name)) { // Export issue: // skip return; } Export(loaded.gameObject); } catch (Exception ex) { Message(gltf.FullName.Substring(subStrStart), ex); } } }
public MeshContext ReadMesh(ImporterContext ctx, int meshIndex) { var gltfMesh = ctx.GLTF.meshes[meshIndex]; var meshContext = new MeshContext(gltfMesh.name, meshIndex); if (HasSharedVertexBuffer(gltfMesh)) { meshContext.ImportMeshSharingVertexBuffer(ctx, gltfMesh); } else { meshContext.ImportMeshIndependentVertexBuffer(ctx, gltfMesh); } meshContext.RenameBlendShape(gltfMesh); meshContext.DropUnusedVertices(); return(meshContext); }
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { foreach (string path in importedAssets) { ImporterContext context = null; var ext = Path.GetExtension(path).ToLower(); try { if (ext == ".gltf") { context = ImportGltf(path, false); } else if (ext == ".glb") { context = ImportGltf(path, true); } if (context != null) { context.SaveAsAsset(); } if (context != null) { context.Destroy(false); } } catch (Exception ex) { Debug.LogErrorFormat("import error: {0}", path); Debug.LogErrorFormat("{0}", ex); if (context != null) { context.Destroy(true); } } } }
public MeshContext ReadMesh(ImporterContext ctx, int meshIndex) { var gltfMesh = ctx.GLTF.meshes[meshIndex]; bool sharedMorphTarget = gltfMesh.extras != null && gltfMesh.extras.targetNames.Count > 0; MeshContext meshContext; if (sharedMorphTarget) { meshContext = _ImportMeshSharingMorphTarget(ctx, gltfMesh); } else { glTFAttributes lastAttributes = null; var sharedAttributes = true; foreach (var prim in gltfMesh.primitives) { if (lastAttributes != null && !prim.attributes.Equals(lastAttributes)) { sharedAttributes = false; break; } lastAttributes = prim.attributes; } meshContext = sharedAttributes ? _ImportMeshSharingVertexBuffer(ctx, gltfMesh) : _ImportMeshIndependentVertexBuffer(ctx, gltfMesh); } meshContext.name = gltfMesh.name; if (string.IsNullOrEmpty(meshContext.name)) { meshContext.name = string.Format("UniGLTF import#{0}", meshIndex); } return(meshContext); }
// // fix node's coordinate. z-back to z-forward // public static void FixCoordinate(ImporterContext context, List<TransformWithSkin> nodes) { var globalTransformMap = nodes.ToDictionary(x => x.Transform, x => new PosRot { Position = x.Transform.position, Rotation = x.Transform.rotation, }); foreach (var x in context.GLTF.rootnodes) { // fix nodes coordinate // reverse Z in global var t = nodes[x].Transform; //t.SetParent(root.transform, false); foreach (var transform in t.Traverse()) { var g = globalTransformMap[transform]; transform.position = g.Position.ReverseZ(); transform.rotation = g.Rotation.ReverseZ(); } } }
public void ImportExportTest() { var path = Path.GetFullPath(Application.dataPath + "/../glTF-Sample-Models/2.0/Box/glTF/Box.gltf"); var context = new ImporterContext(); var bytes = File.ReadAllBytes(path); var importJson = Encoding.UTF8.GetString(bytes); context.ParseJson(importJson, new FileSystemStorage(Path.GetDirectoryName(path))); context.Load(); var gltf = gltfExporter.Export(context.Root); var exportJson = gltf.ToJson(); var l = UniJSON.JsonParser.Parse(importJson); var r = UniJSON.JsonParser.Parse(exportJson); foreach (var diff in l.Diff(r)) { Debug.Log(diff); } //Assert.AreEqual(); }
public static List <AnimationClip> ImportAnimationClip(ImporterContext ctx) { List <AnimationClip> animationClips = new List <AnimationClip>(); for (int i = 0; i < ctx.GLTF.animations.Count; ++i) { var clip = new AnimationClip(); clip.ClearCurves(); clip.legacy = true; clip.name = ctx.GLTF.animations[i].name; if (string.IsNullOrEmpty(clip.name)) { clip.name = "legacy_" + i; } clip.wrapMode = WrapMode.Loop; var animation = ctx.GLTF.animations[i]; if (string.IsNullOrEmpty(animation.name)) { animation.name = string.Format("animation:{0}", i); } foreach (var channel in animation.channels) { var targetTransform = ctx.Nodes[channel.target.node]; var relativePath = targetTransform.RelativePathFrom(ctx.Root.transform); switch (channel.target.path) { case glTFAnimationTarget.PATH_TRANSLATION: { var sampler = animation.samplers[channel.sampler]; var input = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input); var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output); AnimationImporter.SetAnimationCurve( clip, relativePath, new string[] { "localPosition.x", "localPosition.y", "localPosition.z" }, input, output, sampler.interpolation, typeof(Transform), (values, last) => { Vector3 temp = new Vector3(values[0], values[1], values[2]); return(temp.ReverseZ().ToArray()); } ); } break; case glTFAnimationTarget.PATH_ROTATION: { var sampler = animation.samplers[channel.sampler]; var input = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input); var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output); AnimationImporter.SetAnimationCurve( clip, relativePath, new string[] { "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }, input, output, sampler.interpolation, typeof(Transform), (values, last) => { Quaternion currentQuaternion = new Quaternion(values[0], values[1], values[2], values[3]); Quaternion lastQuaternion = new Quaternion(last[0], last[1], last[2], last[3]); return(AnimationImporter.GetShortest(lastQuaternion, currentQuaternion.ReverseZ()).ToArray()); } ); clip.EnsureQuaternionContinuity(); } break; case glTFAnimationTarget.PATH_SCALE: { var sampler = animation.samplers[channel.sampler]; var input = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input); var output = ctx.GLTF.GetArrayFromAccessorAsFloat(sampler.output); AnimationImporter.SetAnimationCurve( clip, relativePath, new string[] { "localScale.x", "localScale.y", "localScale.z" }, input, output, sampler.interpolation, typeof(Transform), (values, last) => values); } break; case glTFAnimationTarget.PATH_WEIGHT: { var node = ctx.GLTF.nodes[channel.target.node]; var mesh = ctx.GLTF.meshes[node.mesh]; //var primitive = mesh.primitives.FirstOrDefault(); //var targets = primitive.targets; List <string> blendShapeNames = new List <string>(); var transform = ctx.Nodes[channel.target.node]; var skinnedMeshRenderer = transform.GetComponent <SkinnedMeshRenderer>(); if (skinnedMeshRenderer == null) { continue; } for (int j = 0; j < skinnedMeshRenderer.sharedMesh.blendShapeCount; j++) { blendShapeNames.Add(skinnedMeshRenderer.sharedMesh.GetBlendShapeName(j)); } var keyNames = blendShapeNames .Where(x => !string.IsNullOrEmpty(x)) .Select(x => "blendShape." + x) .ToArray(); var sampler = animation.samplers[channel.sampler]; var input = ctx.GLTF.GetArrayFromAccessor <float>(sampler.input); var output = ctx.GLTF.GetArrayFromAccessor <float>(sampler.output); AnimationImporter.SetAnimationCurve( clip, relativePath, keyNames, input, output, sampler.interpolation, typeof(SkinnedMeshRenderer), (values, last) => { for (int j = 0; j < values.Length; j++) { values[j] *= 100.0f; } return(values); }); } break; default: Debug.LogWarningFormat("unknown path: {0}", channel.target.path); break; } } animationClips.Add(clip); } return(animationClips); }
public void SameMeshButDifferentMaterialExport() { var go = new GameObject("same_mesh"); try { var shader = Shader.Find("Unlit/Color"); var cubeA = GameObject.CreatePrimitive(PrimitiveType.Cube); { cubeA.transform.SetParent(go.transform); var material = new Material(shader); material.name = "red"; material.color = Color.red; cubeA.GetComponent <Renderer>().sharedMaterial = material; } { var cubeB = GameObject.Instantiate(cubeA); cubeB.transform.SetParent(go.transform); var material = new Material(shader); material.color = Color.blue; material.name = "blue"; cubeB.GetComponent <Renderer>().sharedMaterial = material; Assert.AreEqual(cubeB.GetComponent <MeshFilter>().sharedMesh, cubeA.GetComponent <MeshFilter>().sharedMesh); } // export var gltf = new glTF(); var json = default(string); using (var exporter = new gltfExporter(gltf)) { exporter.Prepare(go); exporter.Export(); json = gltf.ToJson(); } Assert.AreEqual(2, gltf.meshes.Count); var red = gltf.materials[gltf.meshes[0].primitives[0].material]; Assert.AreEqual(new float[] { 1, 0, 0, 1 }, red.pbrMetallicRoughness.baseColorFactor); var blue = gltf.materials[gltf.meshes[1].primitives[0].material]; Assert.AreEqual(new float[] { 0, 0, 1, 1 }, blue.pbrMetallicRoughness.baseColorFactor); Assert.AreEqual(2, gltf.nodes.Count); Assert.AreNotEqual(gltf.nodes[0].mesh, gltf.nodes[1].mesh); // import { var context = new ImporterContext(); context.ParseJson(json, new SimpleStorage(new ArraySegment <byte>(new byte[1024 * 1024]))); //Debug.LogFormat("{0}", context.Json); context.Load(); var importedRed = context.Root.transform.GetChild(0); var importedRedMaterial = importedRed.GetComponent <Renderer>().sharedMaterial; Assert.AreEqual("red", importedRedMaterial.name); Assert.AreEqual(Color.red, importedRedMaterial.color); var importedBlue = context.Root.transform.GetChild(1); var importedBlueMaterial = importedBlue.GetComponent <Renderer>().sharedMaterial; Assert.AreEqual("blue", importedBlueMaterial.name); Assert.AreEqual(Color.blue, importedBlueMaterial.color); } // import new version { var context = new ImporterContext { UseUniJSONParser = true }; context.ParseJson(json, new SimpleStorage(new ArraySegment <byte>(new byte[1024 * 1024]))); //Debug.LogFormat("{0}", context.Json); context.Load(); var importedRed = context.Root.transform.GetChild(0); var importedRedMaterial = importedRed.GetComponent <Renderer>().sharedMaterial; Assert.AreEqual("red", importedRedMaterial.name); Assert.AreEqual(Color.red, importedRedMaterial.color); var importedBlue = context.Root.transform.GetChild(1); var importedBlueMaterial = importedBlue.GetComponent <Renderer>().sharedMaterial; Assert.AreEqual("blue", importedBlueMaterial.name); Assert.AreEqual(Color.blue, importedBlueMaterial.color); } } finally { GameObject.DestroyImmediate(go); } }
async void LoadModelAsync(string path) { if (!File.Exists(path)) { return; } Debug.LogFormat("{0}", path); var ext = Path.GetExtension(path).ToLower(); switch (ext) { case ".vrm": { var data = new GlbFileParser(path).Parse(); using (var context = new VRMImporterContext(data)) { await m_texts.UpdateMetaAsync(context); var loaded = await context.LoadAsync(); loaded.EnableUpdateWhenOffscreen(); loaded.ShowMeshes(); SetModel(loaded.gameObject); } break; } case ".glb": { var data = new GlbFileParser(path).Parse(); var context = new UniGLTF.ImporterContext(data); var loaded = context.Load(); loaded.EnableUpdateWhenOffscreen(); loaded.ShowMeshes(); SetModel(loaded.gameObject); break; } case ".gltf": { var data = new GltfFileWithResourceFilesParser(path).Parse(); var context = new UniGLTF.ImporterContext(data); var loaded = context.Load(); loaded.EnableUpdateWhenOffscreen(); loaded.ShowMeshes(); SetModel(loaded.gameObject); break; } case ".zip": { var data = new ZipArchivedGltfFileParser(path).Parse(); var context = new UniGLTF.ImporterContext(data); var loaded = context.Load(); loaded.EnableUpdateWhenOffscreen(); loaded.ShowMeshes(); SetModel(loaded.gameObject); break; } default: Debug.LogWarningFormat("unknown file type: {0}", path); break; } }