using DepthFirstScheduler; using System; using System.Linq; using System.Collections.Generic; using UniGLTF; using UnityEngine; namespace VRM { public class VRMImporterContext : ImporterContext { const string HUMANOID_KEY = "humanoid"; const string MATERIAL_KEY = "materialProperties"; [Obsolete] public VRMImporterContext(UnityPath gltfPath) : base(gltfPath) { } public VRMImporterContext() { } public override void Load() { MaterialImporter = new VRMMaterialImporter(this, glTF_VRM_Material.Parse(Json)); base.Load(); OnLoadModel(); } protected override Schedulable LoadAsync(bool show) { return Schedulable.Create() .AddTask(Scheduler.ThreadPool, () => { using (MeasureTime("glTF_VRM_Material.Parse")) { return glTF_VRM_Material.Parse(Json); } }) .ContinueWith(Scheduler.MainThread, gltfMaterials => { using (MeasureTime("new VRMMaterialImporter")) { MaterialImporter = new VRMMaterialImporter(this, gltfMaterials); } }) .OnExecute(Scheduler.ThreadPool, parent => { // textures for (int i = 0; i < GLTF.textures.Count; ++i) { var index = i; parent.AddTask(Scheduler.MainThread, () => { using (MeasureTime("texture.Process")) { var texture = new TextureItem(GLTF, index); texture.Process(GLTF, Storage); return texture; } }) .ContinueWith(Scheduler.ThreadPool, x => AddTexture(x)); } }) .ContinueWithCoroutine(Scheduler.MainThread, () => LoadMaterials()) .OnExecute(Scheduler.ThreadPool, parent => { // meshes var meshImporter = new MeshImporter(); for (int i = 0; i < GLTF.meshes.Count; ++i) { var index = i; parent.AddTask(Scheduler.ThreadPool, () => { using (MeasureTime("ReadMesh")) { return meshImporter.ReadMesh(this, index); } }) .ContinueWith(Scheduler.MainThread, x => { using (MeasureTime("BuildMesh")) { return MeshImporter.BuildMesh(this, x); } }) .ContinueWith(Scheduler.ThreadPool, x => Meshes.Add(x)) ; } }) .ContinueWithCoroutine(Scheduler.MainThread, () => { using (MeasureTime("LoadNodes")) { return LoadNodes(); } }) .ContinueWithCoroutine(Scheduler.MainThread, () => { using (MeasureTime("BuildHierarchy")) { return BuildHierarchy(); } }) .ContinueWith(Scheduler.CurrentThread, _ => { //using (MeasureTime("OnLoadModel")) { OnLoadModel(); return Unit.Default; } }) .ContinueWith(Scheduler.CurrentThread, _ => { Root.name = "VRM"; Debug.Log(GetSpeedLog()); return Root; }); } #region OnLoad void OnLoadModel() { using (MeasureTime("VRM LoadMeta")) { LoadMeta(); } using (MeasureTime("VRM LoadHumanoid")) { LoadHumanoid(); } using (MeasureTime("VRM LoadBlendShapeMaster")) { LoadBlendShapeMaster(); } using (MeasureTime("VRM LoadSecondary")) { VRMSpringUtility.LoadSecondary(Root.transform, Nodes, GLTF.extensions.VRM.secondaryAnimation); } using (MeasureTime("VRM LoadFirstPerson")) { LoadFirstPerson(); } } void LoadMeta() { var meta = ReadMeta(); if (meta.Thumbnail == null) { /* // 作る var lookAt = Root.GetComponent(); var thumbnail = lookAt.CreateThumbnail(); thumbnail.name = "thumbnail"; meta.Thumbnail = thumbnail; Textures.Add(new TextureItem(thumbnail)); */ } var _meta = Root.AddComponent(); _meta.Meta = meta; Meta = meta; } void LoadFirstPerson() { var firstPerson = Root.AddComponent(); var gltfFirstPerson = GLTF.extensions.VRM.firstPerson; if (gltfFirstPerson.firstPersonBone != -1) { firstPerson.FirstPersonBone = Nodes[gltfFirstPerson.firstPersonBone]; firstPerson.FirstPersonOffset = gltfFirstPerson.firstPersonBoneOffset; } else { // fallback firstPerson.SetDefault(); } firstPerson.TraverseRenderers(this); // LookAt var lookAtHead = Root.AddComponent(); lookAtHead.OnImported(this); } void LoadBlendShapeMaster() { BlendShapeAvatar = ScriptableObject.CreateInstance(); BlendShapeAvatar.name = "BlendShape"; var blendShapeList = GLTF.extensions.VRM.blendShapeMaster.blendShapeGroups; if (blendShapeList != null && blendShapeList.Count > 0) { foreach (var x in blendShapeList) { BlendShapeAvatar.Clips.Add(LoadBlendShapeBind(x)); } } var proxy = Root.AddComponent(); BlendShapeAvatar.CreateDefaultPreset(); proxy.BlendShapeAvatar = BlendShapeAvatar; } BlendShapeClip LoadBlendShapeBind(glTF_VRM_BlendShapeGroup group) { var asset = ScriptableObject.CreateInstance(); var groupName = group.name; var prefix = "BlendShape."; while (groupName.StartsWith(prefix)) { groupName = groupName.Substring(prefix.Length); } asset.name = "BlendShape." + groupName; if (group != null) { asset.BlendShapeName = groupName; asset.Preset = EnumUtil.TryParseOrDefault(group.presetName); if (asset.Preset == BlendShapePreset.Unknown) { // fallback asset.Preset = EnumUtil.TryParseOrDefault(group.name); } asset.Values = group.binds.Select(x => { var mesh = Meshes[x.mesh].Mesh; var node = Root.transform.Traverse().First(y => y.GetSharedMesh() == mesh); var relativePath = UniGLTF.UnityExtensions.RelativePathFrom(node, Root.transform); return new BlendShapeBinding { RelativePath = relativePath, Index = x.index, Weight = x.weight, }; }) .ToArray(); asset.MaterialValues = group.materialValues.Select(x => { var value = new Vector4(); for (int i = 0; i < x.targetValue.Length; ++i) { switch (i) { case 0: value.x = x.targetValue[0]; break; case 1: value.y = x.targetValue[1]; break; case 2: value.z = x.targetValue[2]; break; case 3: value.w = x.targetValue[3]; break; } } var material = GetMaterials().FirstOrDefault(y => y.name == x.materialName); var propertyName = x.propertyName; if (x.propertyName.EndsWith("_ST_S") || x.propertyName.EndsWith("_ST_T")) { propertyName = x.propertyName.Substring(0, x.propertyName.Length - 2); } var binding = default(MaterialValueBinding?); if (material != null) { try { binding = new MaterialValueBinding { MaterialName = x.materialName, ValueName = x.propertyName, TargetValue = value, BaseValue = material.GetColor(propertyName), }; } catch (Exception) { // do nothing } } return binding; }) .Where(x => x.HasValue) .Select(x => x.Value) .ToArray(); } return asset; } static String ToHumanBoneName(HumanBodyBones b) { foreach (var x in HumanTrait.BoneName) { if (x.Replace(" ", "") == b.ToString()) { return x; } } throw new KeyNotFoundException(); } static SkeletonBone ToSkeletonBone(Transform t) { var sb = new SkeletonBone(); sb.name = t.name; sb.position = t.localPosition; sb.rotation = t.localRotation; sb.scale = t.localScale; return sb; } private void LoadHumanoid() { AvatarDescription = GLTF.extensions.VRM.humanoid.ToDescription(Nodes); AvatarDescription.name = "AvatarDescription"; HumanoidAvatar = AvatarDescription.CreateAvatar(Root.transform); HumanoidAvatar.name = "VrmAvatar"; var humanoid = Root.AddComponent(); humanoid.Avatar = HumanoidAvatar; humanoid.Description = AvatarDescription; var animator = Root.GetComponent(); if (animator == null) { animator = Root.AddComponent(); } animator.avatar = HumanoidAvatar; } #endregion public UniHumanoid.AvatarDescription AvatarDescription; public Avatar HumanoidAvatar; public BlendShapeAvatar BlendShapeAvatar; public VRMMetaObject Meta; public VRMMetaObject ReadMeta(bool createThumbnail = false) { var meta = ScriptableObject.CreateInstance(); meta.name = "Meta"; meta.ExporterVersion = GLTF.extensions.VRM.exporterVersion; var gltfMeta = GLTF.extensions.VRM.meta; meta.Version = gltfMeta.version; // model version meta.Author = gltfMeta.author; meta.ContactInformation = gltfMeta.contactInformation; meta.Reference = gltfMeta.reference; meta.Title = gltfMeta.title; var thumbnail = GetTexture(gltfMeta.texture); if (thumbnail!=null) { // ロード済み meta.Thumbnail = thumbnail.Texture; } else if (createThumbnail) { // 作成する(先行ロード用) if (gltfMeta.texture >= 0 && gltfMeta.texture < GLTF.textures.Count) { var t = new TextureItem(GLTF, gltfMeta.texture); t.Process(GLTF, Storage); meta.Thumbnail = t.Texture; } } meta.AllowedUser = gltfMeta.allowedUser; meta.ViolentUssage = gltfMeta.violentUssage; meta.SexualUssage = gltfMeta.sexualUssage; meta.CommercialUssage = gltfMeta.commercialUssage; meta.OtherPermissionUrl = gltfMeta.otherPermissionUrl; meta.LicenseType = gltfMeta.licenseType; meta.OtherLicenseUrl = gltfMeta.otherLicenseUrl; return meta; } #if UNITY_EDITOR protected override IEnumerable ObjectsForSubAsset() { foreach (var x in base.ObjectsForSubAsset()) { yield return x; } yield return AvatarDescription; yield return HumanoidAvatar; if (BlendShapeAvatar != null && BlendShapeAvatar.Clips != null) { foreach (var x in BlendShapeAvatar.Clips) { yield return x; } } yield return BlendShapeAvatar; yield return Meta; } protected override UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o) { if (o is BlendShapeAvatar || o is BlendShapeClip) { var dir = prefabPath.GetAssetFolder(".BlendShapes"); var assetPath = dir.Child(o.name.EscapeFilePath() + ".asset"); return assetPath; } else { return base.GetAssetPath(prefabPath, o); } } #endif } }