using System; using System.Linq; using System.Collections.Generic; using UnityEngine; using System.IO; using System.Text; #if UNITY_EDITOR using UnityEditor; #endif namespace UniHumanoid { [Obsolete("use BvhImporterContext")] public class ImporterContext: BvhImporterContext { } public class BvhImporterContext { #region Source String m_path; public String Path { get { return m_path; } set { if (m_path == value) return; m_path = value; } } public String Source; // source public Bvh Bvh; #endregion #region Imported public GameObject Root; public List Nodes = new List(); public AnimationClip Animation; public AvatarDescription AvatarDescription; public Avatar Avatar; public Mesh Mesh; public Material Material; #endregion #region Load [Obsolete("use Load(path)")] public void Parse() { Parse(Path); } public void Parse(string path) { Path = path; Source = File.ReadAllText(Path, Encoding.UTF8); Bvh = Bvh.Parse(Source); } public void Load() { // // build hierarchy // Root = new GameObject(System.IO.Path.GetFileNameWithoutExtension(Path)); var hips = BuildHierarchy(Root.transform, Bvh.Root, 1.0f); var skeleton = Skeleton.Estimate(hips); var description = AvatarDescription.Create(hips.Traverse().ToArray(), skeleton); // // scaling. reposition // float scaling = 1.0f; { //var foot = animator.GetBoneTransform(HumanBodyBones.LeftFoot); var foot = hips.Traverse().Skip(skeleton.GetBoneIndex(HumanBodyBones.LeftFoot)).First(); var hipHeight = hips.position.y - foot.position.y; // hips height to a meter scaling = 1.0f / hipHeight; foreach (var x in Root.transform.Traverse()) { x.localPosition *= scaling; } var scaledHeight = hipHeight * scaling; hips.position = new Vector3(0, scaledHeight, 0); // foot to ground } // // avatar // Avatar = description.CreateAvatar(Root.transform); Avatar.name = "Avatar"; AvatarDescription = description; var animator = Root.AddComponent(); animator.avatar = Avatar; // // create AnimationClip // Animation = BvhAnimation.CreateAnimationClip(Bvh, scaling); Animation.name = Root.name; Animation.legacy = true; Animation.wrapMode = WrapMode.Loop; var animation = Root.AddComponent(); animation.AddClip(Animation, Animation.name); animation.clip = Animation; animation.Play(); var humanPoseTransfer = Root.AddComponent(); humanPoseTransfer.Avatar = Avatar; // create SkinnedMesh for bone visualize var renderer = SkeletonMeshUtility.CreateRenderer(animator); Material = new Material(Shader.Find("Standard")); renderer.sharedMaterial = Material; Mesh = renderer.sharedMesh; Mesh.name = "box-man"; Root.AddComponent(); } static Transform BuildHierarchy(Transform parent, BvhNode node, float toMeter) { var go = new GameObject(node.Name); go.transform.localPosition = node.Offset.ToXReversedVector3() * toMeter; go.transform.SetParent(parent, false); //var gizmo = go.AddComponent(); //gizmo.Draw = true; foreach (var child in node.Children) { BuildHierarchy(go.transform, child, toMeter); } return go.transform; } #endregion #if UNITY_EDITOR protected virtual string GetPrefabPath() { var dir = System.IO.Path.GetDirectoryName(Path); var name = System.IO.Path.GetFileNameWithoutExtension(Path); var prefabPath = string.Format("{0}/{1}.prefab", dir, name); if (!Application.isPlaying && File.Exists(prefabPath)) { // already exists if (IsOwn(prefabPath)) { //Debug.LogFormat("already exist. own: {0}", prefabPath); } else { // but unknown prefab var unique = AssetDatabase.GenerateUniqueAssetPath(prefabPath); //Debug.LogFormat("already exist: {0} => {1}", prefabPath, unique); prefabPath = unique; } } return prefabPath; } #region Assets IEnumerable GetSubAssets(string path) { return AssetDatabase.LoadAllAssetsAtPath(path); } protected virtual bool IsOwn(string path) { foreach (var x in GetSubAssets(path)) { //if (x is Transform) continue; if (x is GameObject) continue; if (x is Component) continue; if (AssetDatabase.IsSubAsset(x)) { return true; } } return false; } IEnumerable ObjectsForSubAsset() { if (Animation != null) yield return Animation; if (AvatarDescription != null) yield return AvatarDescription; if (Avatar != null) yield return Avatar; if (Mesh != null) yield return Mesh; if (Material != null) yield return Material; } public void SaveAsAsset() { var path = GetPrefabPath(); if (File.Exists(path)) { // clear SubAssets foreach (var x in GetSubAssets(path).Where(x => !(x is GameObject) && !(x is Component))) { GameObject.DestroyImmediate(x, true); } } // Add SubAsset foreach (var o in ObjectsForSubAsset()) { AssetDatabase.AddObjectToAsset(o, path); } // Create or upate Main Asset if (File.Exists(path)) { Debug.LogFormat("replace prefab: {0}", path); var prefab = AssetDatabase.LoadAssetAtPath(path); PrefabUtility.ReplacePrefab(Root, prefab, ReplacePrefabOptions.ReplaceNameBased); } else { Debug.LogFormat("create prefab: {0}", path); PrefabUtility.CreatePrefab(path, Root); } AssetDatabase.ImportAsset(path); } #endregion #endif public void Destroy(bool destroySubAssets) { if (Root != null) GameObject.DestroyImmediate(Root); if (destroySubAssets) { #if UNITY_EDITOR foreach (var o in ObjectsForSubAsset()) { UnityEngine.Object.DestroyImmediate(o, true); } #endif } } } }