/// <summary>
        /// モデルの正規化を実行する
        /// </summary>
        /// <param name="go">対象モデルのルート</param>
        /// <param name="forceTPose">強制的にT-Pose化するか</param>
        /// <returns>正規化済みのモデル</returns>
        public static GameObject Execute(GameObject go, bool forceTPose)
        {
            //
            // T-Poseにする
            //
            if (forceTPose)
            {
                var hips         = go.GetComponent <Animator>().GetBoneTransform(HumanBodyBones.Hips);
                var hipsPosition = hips.position;
                var hipsRotation = hips.rotation;
                try
                {
                    EnforceTPose(go);
                }
                finally
                {
                    hips.position = hipsPosition; // restore hipsPosition
                    hips.rotation = hipsRotation;
                }
            }

            //
            // 正規化されたヒエラルキーを作る
            //
            var(normalized, bMap) = MeshUtility.BoneNormalizer.Execute(go, (_src, dst, boneMap) =>
            {
                var src = _src.GetComponent <Animator>();

                var srcHumanBones = Enum.GetValues(typeof(HumanBodyBones))
                                    .Cast <HumanBodyBones>()
                                    .Where(x => x != HumanBodyBones.LastBone)
                                    .Select(x => new { Key = x, Value = src.GetBoneTransform(x) })
                                    .Where(x => x.Value != null)
                ;

                var map =
                    srcHumanBones
                    .Where(x => boneMap.ContainsKey(x.Value))
                    .ToDictionary(x => x.Key, x => boneMap[x.Value])
                ;

                if (dst.GetComponent <Animator>() == null)
                {
                    var animator = dst.AddComponent <Animator>();
                }
                var vrmHuman          = go.GetComponent <VRMHumanoidDescription>();
                var avatarDescription = AvatarDescription.Create();
                if (vrmHuman != null && vrmHuman.Description != null)
                {
                    avatarDescription.armStretch        = vrmHuman.Description.armStretch;
                    avatarDescription.legStretch        = vrmHuman.Description.legStretch;
                    avatarDescription.upperArmTwist     = vrmHuman.Description.upperArmTwist;
                    avatarDescription.lowerArmTwist     = vrmHuman.Description.lowerArmTwist;
                    avatarDescription.upperLegTwist     = vrmHuman.Description.upperLegTwist;
                    avatarDescription.lowerLegTwist     = vrmHuman.Description.lowerLegTwist;
                    avatarDescription.feetSpacing       = vrmHuman.Description.feetSpacing;
                    avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF;
                }
                avatarDescription.SetHumanBones(map);
                var avatar = avatarDescription.CreateAvatar(dst.transform);
                return(avatar);
            });

            CopyVRMComponents(go, normalized, bMap);

            return(normalized);
        }
Esempio n. 2
0
        public static GameObject Execute(GameObject go, Dictionary <Transform, Transform> boneMap, bool forceTPose)
        {
            //
            // T-Poseにする
            //
            if (forceTPose)
            {
                var animator = go.GetComponent <Animator>();
                if (animator == null)
                {
                    throw new ArgumentException("Animator with avatar is required");
                }

                var avatar = animator.avatar;
                if (avatar == null)
                {
                    throw new ArgumentException("avatar is required");
                }

                if (!avatar.isValid)
                {
                    throw new ArgumentException("invalid avatar");
                }

                if (!avatar.isHuman)
                {
                    throw new ArgumentException("avatar is not human");
                }

                HumanPoseTransfer.SetTPose(avatar, go.transform);
            }

            //
            // 回転・スケールの無いヒエラルキーをコピーする
            //
            var normalized = new GameObject(go.name + "(normalized)");

            normalized.transform.position = go.transform.position;

            CopyAndBuild(go.transform, normalized.transform, boneMap);

            //
            // 新しいヒエラルキーからAvatarを作る
            //
            {
                var src = go.GetComponent <Animator>();

                var map = Enum.GetValues(typeof(HumanBodyBones))
                          .Cast <HumanBodyBones>()
                          .Where(x => x != HumanBodyBones.LastBone)
                          .Select(x => new { Key = x, Value = src.GetBoneTransform(x) })
                          .Where(x => x.Value != null)
                          .ToDictionary(x => x.Key, x => boneMap[x.Value])
                ;

                var animator          = normalized.AddComponent <Animator>();
                var vrmHuman          = go.GetComponent <VRMHumanoidDescription>();
                var avatarDescription = AvatarDescription.Create();
                if (vrmHuman != null && vrmHuman.Description != null)
                {
                    avatarDescription.armStretch        = vrmHuman.Description.armStretch;
                    avatarDescription.legStretch        = vrmHuman.Description.legStretch;
                    avatarDescription.upperArmTwist     = vrmHuman.Description.upperArmTwist;
                    avatarDescription.lowerArmTwist     = vrmHuman.Description.lowerArmTwist;
                    avatarDescription.upperLegTwist     = vrmHuman.Description.upperLegTwist;
                    avatarDescription.lowerLegTwist     = vrmHuman.Description.lowerLegTwist;
                    avatarDescription.feetSpacing       = vrmHuman.Description.feetSpacing;
                    avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF;
                }
                avatarDescription.SetHumanBones(map);
                var avatar = avatarDescription.CreateAvatar(normalized.transform);

                avatar.name     = go.name + ".normalized";
                animator.avatar = avatar;

                var humanPoseTransfer = normalized.AddComponent <HumanPoseTransfer>();
                humanPoseTransfer.Avatar = avatar;
            }

            //
            // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する
            //
            foreach (var src in go.transform.Traverse())
            {
                Transform dst;
                if (!boneMap.TryGetValue(src, out dst))
                {
                    continue;
                }

                {
                    //
                    // SkinnedMesh
                    //
                    var srcRenderer = src.GetComponent <SkinnedMeshRenderer>();
                    if (srcRenderer != null && srcRenderer.enabled &&
                        srcRenderer.sharedMesh != null &&
                        srcRenderer.sharedMesh.vertexCount > 0)
                    {
                        // clear blendShape
                        var srcMesh = srcRenderer.sharedMesh;
                        for (int i = 0; i < srcMesh.blendShapeCount; ++i)
                        {
                            srcRenderer.SetBlendShapeWeight(i, 0);
                        }

                        var mesh = new Mesh();
                        mesh.name = srcMesh.name + ".baked";
#if UNITY_2017_3_OR_NEWER
                        mesh.indexFormat = srcMesh.indexFormat;
#endif

                        srcRenderer.BakeMesh(mesh);

                        //var m = src.localToWorldMatrix;
                        var m = default(Matrix4x4);
                        m.SetTRS(Vector3.zero, src.rotation, Vector3.one);

                        mesh.vertices = mesh.vertices.Select(x => m.MultiplyPoint(x)).ToArray();
                        mesh.normals  = mesh.normals.Select(x => m.MultiplyVector(x).normalized).ToArray();

                        mesh.uv           = srcMesh.uv;
                        mesh.tangents     = srcMesh.tangents;
                        mesh.subMeshCount = srcMesh.subMeshCount;
                        for (int i = 0; i < srcMesh.subMeshCount; ++i)
                        {
                            mesh.SetIndices(srcMesh.GetIndices(i), srcMesh.GetTopology(i), i);
                        }

                        // boneweights
                        var bones = srcRenderer.bones.Select(x => boneMap[x]).ToArray();
                        if (bones.Length > 0)
                        {
                            mesh.boneWeights = srcMesh.boneWeights;
                        }
                        else
                        {
                            Debug.LogFormat("no weight: {0}", srcMesh.name);
                            bones = new[] { boneMap[srcRenderer.transform] };
                            var bw = new BoneWeight
                            {
                                boneIndex0 = 0,
                                boneIndex1 = 0,
                                boneIndex2 = 0,
                                boneIndex3 = 0,
                                weight0    = 1.0f,
                                weight1    = 0.0f,
                                weight2    = 0.0f,
                                weight3    = 0.0f,
                            };
                            mesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray();
                        }

                        var meshVertices = mesh.vertices;
                        var meshNormals  = mesh.normals;
                        var meshTangents = mesh.tangents.Select(x => (Vector3)x).ToArray();

                        var _meshVertices = new Vector3[meshVertices.Length];
                        var _meshNormals  = new Vector3[meshVertices.Length];
                        var _meshTangents = new Vector3[meshVertices.Length];

                        var blendShapeMesh = new Mesh();
                        for (int i = 0; i < srcMesh.blendShapeCount; ++i)
                        {
                            // check blendShape
                            srcRenderer.sharedMesh.GetBlendShapeFrameVertices(i, 0, _meshVertices, _meshNormals, _meshTangents);
                            var hasVertices = !_meshVertices.All(x => x == Vector3.zero);
                            var hasNormals  = !_meshNormals.All(x => x == Vector3.zero);
                            var hasTangents = !_meshTangents.All(x => x == Vector3.zero);

                            srcRenderer.SetBlendShapeWeight(i, 100.0f);
                            srcRenderer.BakeMesh(blendShapeMesh);
                            if (blendShapeMesh.vertices.Length != mesh.vertices.Length)
                            {
                                throw new Exception("diffrent vertex count");
                            }
                            srcRenderer.SetBlendShapeWeight(i, 0);

                            Vector3[] vertices = null;
                            if (hasVertices)
                            {
                                vertices = blendShapeMesh.vertices;
                                // to delta
                                for (int j = 0; j < vertices.Length; ++j)
                                {
                                    vertices[j] = m.MultiplyPoint(vertices[j]) - meshVertices[j];
                                }
                            }
                            else
                            {
                                vertices = new Vector3[mesh.vertexCount];
                            }

                            Vector3[] normals = null;
                            if (hasNormals)
                            {
                                normals = blendShapeMesh.normals;
                                // to delta
                                for (int j = 0; j < normals.Length; ++j)
                                {
                                    normals[j] = m.MultiplyVector(normals[j]) - meshNormals[j];
                                }
                            }
                            else
                            {
                                normals = new Vector3[mesh.vertexCount];
                            }

                            Vector3[] tangents = null;
                            if (hasTangents)
                            {
                                tangents = blendShapeMesh.tangents.Select(x => (Vector3)x).ToArray();
                                // to delta
                                for (int j = 0; j < tangents.Length; ++j)
                                {
                                    tangents[j] = m.MultiplyVector(tangents[j]) - meshTangents[j];
                                }
                            }
                            else
                            {
                                tangents = new Vector3[mesh.vertexCount];
                            }

                            var name = srcMesh.GetBlendShapeName(i);
                            if (string.IsNullOrEmpty(name))
                            {
                                name = String.Format("{0}", i);
                            }

                            var weight = srcMesh.GetBlendShapeFrameWeight(i, 0);

                            try
                            {
                                mesh.AddBlendShapeFrame(name,
                                                        weight,
                                                        vertices,
                                                        normals,
                                                        tangents
                                                        );
                            }
                            catch (Exception)
                            {
                                Debug.LogErrorFormat("fail to mesh.AddBlendShapeFrame {0}.{1}",
                                                     mesh.name,
                                                     srcMesh.GetBlendShapeName(i)
                                                     );
                                throw;
                            }
                        }

                        // recalc bindposes
                        mesh.bindposes = bones.Select(x =>
                                                      x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray();

                        mesh.RecalculateBounds();

                        var dstRenderer = dst.gameObject.AddComponent <SkinnedMeshRenderer>();
                        dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
                        dstRenderer.sharedMesh      = mesh;
                        dstRenderer.bones           = bones;
                        if (srcRenderer.rootBone != null)
                        {
                            dstRenderer.rootBone = boneMap[srcRenderer.rootBone];
                        }
                    }
                }

                {
                    //
                    // not SkinnedMesh
                    //
                    var srcFilter = src.GetComponent <MeshFilter>();
                    if (srcFilter != null &&
                        srcFilter.sharedMesh != null &&
                        srcFilter.sharedMesh.vertexCount > 0)
                    {
                        var srcRenderer = src.GetComponent <MeshRenderer>();
                        if (srcRenderer != null && srcRenderer.enabled)
                        {
                            var dstFilter = dst.gameObject.AddComponent <MeshFilter>();
                            dstFilter.sharedMesh = TransformMesh(srcFilter.sharedMesh, src.localToWorldMatrix);

                            var dstRenderer = dst.gameObject.AddComponent <MeshRenderer>();
                            dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
                        }
                    }
                }
            }

            return(normalized);
        }
Esempio n. 3
0
        public AdvancedAvatarRagdollSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            // This sample uses for a DebugRenderer to draw text and rigid bodies.
            _debugRenderer = new DebugRenderer(GraphicsService, SpriteFont)
            {
                DefaultColor        = Color.Black,
                DefaultTextPosition = new Vector2F(10),
            };

            // Add a custom game object which controls the camera.
            _cameraObject = new CameraObject(Services);
            _cameraObject.ResetPose(new Vector3F(0, 1, -3), ConstantsF.Pi, 0);
            GameObjectService.Objects.Add(_cameraObject);

            // Add some objects which allow the user to interact with the rigid bodies.
            _grabObject        = new GrabObject(Services);
            _ballShooterObject = new BallShooterObject(Services)
            {
                Speed = 20
            };
            GameObjectService.Objects.Add(_grabObject);
            GameObjectService.Objects.Add(_ballShooterObject);

            // Add some default force effects.
            Simulation.ForceEffects.Add(new Gravity());
            Simulation.ForceEffects.Add(new Damping());

            // Create a random avatar.
            _avatarDescription = AvatarDescription.CreateRandom();
            _avatarRenderer    = new AvatarRenderer(_avatarDescription);

            // Use the "Wave" animation preset.
            var avatarAnimation = new AvatarAnimation(AvatarAnimationPreset.Wave);

            _expressionAnimation = new AnimationClip <AvatarExpression>(new WrappedAvatarExpressionAnimation(avatarAnimation))
            {
                LoopBehavior = LoopBehavior.Cycle,
                Duration     = TimeSpan.MaxValue,
            };
            _skeletonAnimation = new AnimationClip <SkeletonPose>(new WrappedAvatarSkeletonAnimation(avatarAnimation))
            {
                LoopBehavior = LoopBehavior.Cycle,
                Duration     = TimeSpan.MaxValue,
            };

            // Add a ground plane in the simulation.
            Simulation.RigidBodies.Add(new RigidBody(new PlaneShape(Vector3F.UnitY, 0))
            {
                MotionType = MotionType.Static
            });

            // Distribute a few dynamic spheres and boxes across the landscape.
            SphereShape sphereShape = new SphereShape(0.3f);

            for (int i = 0; i < 10; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-10, 10);
                position.Y = 1;
                Simulation.RigidBodies.Add(new RigidBody(sphereShape)
                {
                    Pose = new Pose(position)
                });
            }

            BoxShape boxShape = new BoxShape(0.6f, 0.6f, 0.6f);

            for (int i = 0; i < 10; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-10, 10);
                position.Y = 1;
                Simulation.RigidBodies.Add(new RigidBody(boxShape)
                {
                    Pose = new Pose(position)
                });
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Load the avatar for a gamer
        /// </summary>
        private void LoadAvatar(Gamer gamer)
        {
            UnloadAvatar();

            AvatarDescription.BeginGetFromGamer(gamer, LoadAvatarDescription, null);
        }
Esempio n. 5
0
        public static GameObject Execute(GameObject go, Dictionary <Transform, Transform> boneMap, bool forceTPose)
        {
            //
            // T-Poseにする
            //
            if (forceTPose)
            {
                var animator = go.GetComponent <Animator>();
                if (animator == null)
                {
                    throw new ArgumentException("Animator with avatar is required");
                }

                var avatar = animator.avatar;
                if (avatar == null)
                {
                    throw new ArgumentException("avatar is required");
                }

                if (!avatar.isValid)
                {
                    throw new ArgumentException("invalid avatar");
                }

                if (!avatar.isHuman)
                {
                    throw new ArgumentException("avatar is not human");
                }

                HumanPoseTransfer.SetTPose(avatar, go.transform);
            }

            //
            // 回転・スケールの無いヒエラルキーをコピーする
            //
            var normalized = new GameObject(go.name + "(normalized)");

            normalized.transform.position = go.transform.position;

            CopyAndBuild(go.transform, normalized.transform, boneMap);

            //
            // 新しいヒエラルキーからAvatarを作る
            //
            {
                var src = go.GetComponent <Animator>();

                var map = Enum.GetValues(typeof(HumanBodyBones))
                          .Cast <HumanBodyBones>()
                          .Where(x => x != HumanBodyBones.LastBone)
                          .Select(x => new { Key = x, Value = src.GetBoneTransform(x) })
                          .Where(x => x.Value != null)
                          .ToDictionary(x => x.Key, x => boneMap[x.Value])
                ;

                var animator          = normalized.AddComponent <Animator>();
                var vrmHuman          = go.GetComponent <VRMHumanoidDescription>();
                var avatarDescription = AvatarDescription.Create();
                if (vrmHuman != null && vrmHuman.Description != null)
                {
                    avatarDescription.armStretch        = vrmHuman.Description.armStretch;
                    avatarDescription.legStretch        = vrmHuman.Description.legStretch;
                    avatarDescription.upperArmTwist     = vrmHuman.Description.upperArmTwist;
                    avatarDescription.lowerArmTwist     = vrmHuman.Description.lowerArmTwist;
                    avatarDescription.upperLegTwist     = vrmHuman.Description.upperLegTwist;
                    avatarDescription.lowerLegTwist     = vrmHuman.Description.lowerLegTwist;
                    avatarDescription.feetSpacing       = vrmHuman.Description.feetSpacing;
                    avatarDescription.hasTranslationDoF = vrmHuman.Description.hasTranslationDoF;
                }
                avatarDescription.SetHumanBones(map);
                var avatar = avatarDescription.CreateAvatar(normalized.transform);

                avatar.name     = go.name + ".normalized";
                animator.avatar = avatar;

                var humanPoseTransfer = normalized.AddComponent <HumanPoseTransfer>();
                humanPoseTransfer.Avatar = avatar;
            }

            //
            // 各メッシュから回転・スケールを取り除いてBinding行列を再計算する
            //
            foreach (var src in go.transform.Traverse())
            {
                var dst = boneMap[src];

                {
                    //
                    // SkinnedMesh
                    //
                    var srcRenderer = src.GetComponent <SkinnedMeshRenderer>();
                    if (srcRenderer != null && srcRenderer.enabled)
                    {
                        // clear blendShape
                        var srcMesh = srcRenderer.sharedMesh;
                        for (int i = 0; i < srcMesh.blendShapeCount; ++i)
                        {
                            srcRenderer.SetBlendShapeWeight(i, 0);
                        }

                        var mesh = new Mesh();
                        mesh.name = srcMesh.name + ".baked";
                        srcRenderer.BakeMesh(mesh);

                        //var m = src.localToWorldMatrix;
                        var m = default(Matrix4x4);
                        m.SetTRS(Vector3.zero, src.rotation, Vector3.one);

                        mesh.vertices = mesh.vertices.Select(x => m.MultiplyPoint(x)).ToArray();
                        mesh.normals  = mesh.normals.Select(x => m.MultiplyVector(x).normalized).ToArray();

                        mesh.uv           = srcMesh.uv;
                        mesh.tangents     = srcMesh.tangents;
                        mesh.subMeshCount = srcMesh.subMeshCount;
                        for (int i = 0; i < srcMesh.subMeshCount; ++i)
                        {
                            mesh.SetIndices(srcMesh.GetIndices(i), srcMesh.GetTopology(i), i);
                        }
                        mesh.boneWeights = srcMesh.boneWeights;

                        var meshVertices   = mesh.vertices;
                        var blendShapeMesh = new Mesh();
                        for (int i = 0; i < srcMesh.blendShapeCount; ++i)
                        {
                            srcRenderer.SetBlendShapeWeight(i, 100.0f);
                            srcRenderer.BakeMesh(blendShapeMesh);
                            srcRenderer.SetBlendShapeWeight(i, 0);

                            if (blendShapeMesh.vertices.Length != mesh.vertices.Length)
                            {
                                throw new Exception("diffrent vertex count");
                            }

                            var weight   = srcMesh.GetBlendShapeFrameWeight(i, 0);
                            var vertices = blendShapeMesh.vertices;
                            var normals  = blendShapeMesh.normals;
                            var tangents = blendShapeMesh.tangents.Select(x => (Vector3)x).ToArray();

                            for (int j = 0; j < vertices.Length; ++j)
                            {
                                vertices[j] = m.MultiplyPoint(vertices[j]) - meshVertices[j];
                            }
                            for (int j = 0; j < normals.Length; ++j)
                            {
                                normals[j] = m.MultiplyVector(normals[j]).normalized;
                            }
                            for (int j = 0; j < tangents.Length; ++j)
                            {
                                tangents[j] = m.MultiplyVector(tangents[j]).normalized;
                            }

                            var name = srcMesh.GetBlendShapeName(i);
                            if (string.IsNullOrEmpty(name))
                            {
                                name = String.Format("{0}", i);
                            }

                            try
                            {
                                mesh.AddBlendShapeFrame(name,
                                                        weight,
                                                        vertices.Length == meshVertices.Length ? vertices : null,
                                                        normals.Length == meshVertices.Length ? normals : null,
                                                        tangents.Length == meshVertices.Length ? tangents : null
                                                        );
                            }
                            catch (Exception)
                            {
                                Debug.LogWarningFormat("{0}.{1}", mesh.name, srcMesh.GetBlendShapeName(i));

                                throw;
                            }
                        }

                        // recalc bindposes
                        var bones = srcRenderer.bones.Select(x => boneMap[x]).ToArray();
                        mesh.bindposes = bones.Select(x =>
                                                      x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray();

                        mesh.RecalculateBounds();

                        var dstRenderer = dst.gameObject.AddComponent <SkinnedMeshRenderer>();
                        dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
                        dstRenderer.sharedMesh      = mesh;
                        dstRenderer.bones           = bones;
                        if (srcRenderer.rootBone != null)
                        {
                            dstRenderer.rootBone = boneMap[srcRenderer.rootBone];
                        }
                    }
                }

                {
                    //
                    // not SkinnedMesh
                    //
                    var srcFilter = src.GetComponent <MeshFilter>();
                    if (srcFilter != null)
                    {
                        var srcRenderer = src.GetComponent <MeshRenderer>();
                        if (srcRenderer != null && srcRenderer.enabled)
                        {
                            var dstFilter = dst.gameObject.AddComponent <MeshFilter>();
                            dstFilter.sharedMesh = srcFilter.sharedMesh;

                            var dstRenderer = dst.gameObject.AddComponent <MeshRenderer>();
                            dstRenderer.sharedMaterials = srcRenderer.sharedMaterials;
                        }
                    }
                }
            }

            return(normalized);
        }
Esempio n. 6
0
    public static void Import(ImporterContext context)
    {
        //
        // parse
        //
        // context.Source = File.ReadAllText(context.Path, Encoding.UTF8);
        context.Bvh = Bvh.Parse(context.Source);
        Debug.LogFormat("parsed {0}", context.Bvh);

        //
        // build hierarchy
        //
        context.Root = new GameObject(Path.GetFileNameWithoutExtension(context.Path));

        BuildHierarchy(context.Root.transform, context.Bvh.Root, 1.0f);

        var hips        = context.Root.transform.GetChild(0);
        var estimater   = new BvhSkeletonEstimator();
        var skeleton    = estimater.Detect(hips.transform);
        var description = AvatarDescription.Create();

        //var values= ((HumanBodyBones[])Enum.GetValues(typeof(HumanBodyBones)));
        description.SetHumanBones(skeleton.ToDictionary(hips.Traverse().ToArray()));

        //
        // 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 context.Root.transform.Traverse())
            {
                x.localPosition *= scaling;
            }

            var scaledHeight = hipHeight * scaling;
            hips.position = new Vector3(0, scaledHeight, 0); // foot to ground
        }

        //
        // avatar
        //
        context.Avatar            = description.CreateAvatar(context.Root.transform);
        context.Avatar.name       = "Avatar";
        context.AvatarDescription = description;
        var animator = context.Root.AddComponent <Animator>();

        animator.avatar = context.Avatar;

        //
        // create AnimationClip
        //
        context.Animation          = BvhAnimation.CreateAnimationClip(context.Bvh, scaling);
        context.Animation.name     = context.Root.name;
        context.Animation.legacy   = true;
        context.Animation.wrapMode = WrapMode.Loop;

        var animation = context.Root.AddComponent <Animation>();

        animation.AddClip(context.Animation, context.Animation.name);
        animation.clip = context.Animation;
        animation.Play();

        var humanPoseTransfer = context.Root.AddComponent <HumanPoseTransfer>();

        humanPoseTransfer.Avatar = context.Avatar;

        // create SkinnedMesh for bone visualize
        var renderer = SkeletonMeshUtility.CreateRenderer(animator);

        context.Material        = new Material(Shader.Find("Standard"));
        renderer.sharedMaterial = context.Material;
        context.Mesh            = renderer.sharedMesh;
        context.Mesh.name       = "box-man";

        context.Root.AddComponent <BoneMapping>();
    }