예제 #1
0
        /// <summary>
        /// Places the end of a bone here, unless the bone level would become too high, or too many bones have been added already.
        /// The bone's origin is at the previously added bone (as seen from the current state).
        /// </summary>
        /// <param name="delta">Amount to adjust the current bone level by</param>
        /// <remarks>
        /// Branches added between this and the previously added bone will be controlled by the new bone.
        /// 
        /// The current bone is part of the crayon's state, like position and rotation, and is affected by PushState and PopState.
        /// </remarks>
        public void Bone(int delta)
        {
            if (state.BoneLevel > boneLevels + delta || skeleton.Bones.Count == MaxBones)
                return;

            // Get index of the parent
            int parent = state.ParentBoneIndex;

            // Get the parent's absolute transform
            Matrix parentTransform = Matrix.Identity;
            Matrix parentInverseTransform = Matrix.Identity;
            float parentLength = 0.0f;
            if (parent != -1)
            {
                parentTransform = skeleton.Bones[parent].ReferenceTransform;
                parentInverseTransform = skeleton.Bones[parent].InverseReferenceTransform;
                parentLength = skeleton.Bones[parent].Length;
            }

            // Find the starting and ending point of the new bone
            Vector3 targetLocation = GetTransform().Translation;
            Vector3 fromLocation = parentTransform.Translation + parentTransform.Up * parentLength;

            // Direction of the bone's Y-axis
            Vector3 directionY = Vector3.Normalize(targetLocation - fromLocation);

            // Choose arbitrary perpendicular X and Z axes
            Vector3 directionX;
            Vector3 directionZ;
            if (directionY.Y < 0.50f)
            {
                directionX = Vector3.Normalize(Vector3.Cross(directionY, Vector3.Up));
                directionZ = Vector3.Normalize(Vector3.Cross(directionX, directionY));
            }
            else
            {
                directionX = Vector3.Normalize(Vector3.Cross(directionY, Vector3.Backward));
                directionZ = Vector3.Normalize(Vector3.Cross(directionX, directionY));
            }

            // Construct the absolute rotation of the child
            Matrix childAbsoluteTransform = Matrix.Identity;
            childAbsoluteTransform.Right = directionX;
            childAbsoluteTransform.Up = directionY;
            childAbsoluteTransform.Backward = directionZ;
            childAbsoluteTransform.Translation = fromLocation;

            // Calculate the relative transformation
            Matrix relativeTransformation = childAbsoluteTransform * parentInverseTransform;
            Quaternion rotation = Quaternion.CreateFromRotationMatrix(relativeTransformation);

            // Create the new bone
            TreeBone bone = new TreeBone();
            bone.ReferenceTransform = childAbsoluteTransform;
            bone.InverseReferenceTransform = Matrix.Invert(bone.ReferenceTransform);
            bone.Length = Vector3.Distance(fromLocation, targetLocation);
            bone.Rotation = rotation;
            bone.ParentIndex = parent;
            bone.Stiffness = skeleton.Branches[state.ParentIndex].StartRadius; // 1.0f; // TODO: Set stiffness according to radius
            bone.EndBranchIndex = state.ParentIndex;

            // Add the bone to the skeleton
            skeleton.Bones.Add(bone);

            // Set this bone as the parent
            int endIndex = (state.ParentBoneIndex == -1? -1 : skeleton.Bones[state.ParentBoneIndex].EndBranchIndex);
            int boneIndex = state.ParentBoneIndex = skeleton.Bones.Count - 1;
            state.BoneLevel -= delta;

            // Update the bone index on branches
            int branchIndex = state.ParentIndex;
            while (branchIndex != endIndex)
            {
                TreeBranch branch = skeleton.Branches[branchIndex];
                branch.BoneIndex = boneIndex;
                skeleton.Branches[branchIndex] = branch;
                branchIndex = branch.ParentIndex;
            }
        }
        /// <summary>
        /// Places the end of a bone here, unless the bone level would become too high, or too many bones have been added already.
        /// The bone's origin is at the previously added bone (as seen from the current state).
        /// </summary>
        /// <param name="delta">Amount to adjust the current bone level by</param>
        /// <remarks>
        /// Branches added between this and the previously added bone will be controlled by the new bone.
        ///
        /// The current bone is part of the crayon's state, like position and rotation, and is affected by PushState and PopState.
        /// </remarks>
        public void Bone(int delta)
        {
            if (state.BoneLevel > boneLevels + delta || skeleton.Bones.Count == MaxBones)
            {
                return;
            }

            // Get index of the parent
            int parent = state.ParentBoneIndex;

            // Get the parent's absolute transform
            Matrix parentTransform        = Matrix.Identity;
            Matrix parentInverseTransform = Matrix.Identity;
            float  parentLength           = 0.0f;

            if (parent != -1)
            {
                parentTransform        = skeleton.Bones[parent].ReferenceTransform;
                parentInverseTransform = skeleton.Bones[parent].InverseReferenceTransform;
                parentLength           = skeleton.Bones[parent].Length;
            }

            // Find the starting and ending point of the new bone
            Vector3 targetLocation = GetTransform().Translation;
            Vector3 fromLocation   = parentTransform.Translation + parentTransform.Up * parentLength;

            // Direction of the bone's Y-axis
            Vector3 directionY = Vector3.Normalize(targetLocation - fromLocation);

            // Choose arbitrary perpendicular X and Z axes
            Vector3 directionX;
            Vector3 directionZ;

            if (directionY.Y < 0.50f)
            {
                directionX = Vector3.Normalize(Vector3.Cross(directionY, Vector3.Up));
                directionZ = Vector3.Normalize(Vector3.Cross(directionX, directionY));
            }
            else
            {
                directionX = Vector3.Normalize(Vector3.Cross(directionY, Vector3.Backward));
                directionZ = Vector3.Normalize(Vector3.Cross(directionX, directionY));
            }

            // Construct the absolute rotation of the child
            Matrix childAbsoluteTransform = Matrix.Identity;

            childAbsoluteTransform.Right       = directionX;
            childAbsoluteTransform.Up          = directionY;
            childAbsoluteTransform.Backward    = directionZ;
            childAbsoluteTransform.Translation = fromLocation;

            // Calculate the relative transformation
            Matrix     relativeTransformation = childAbsoluteTransform * parentInverseTransform;
            Quaternion rotation = Quaternion.CreateFromRotationMatrix(relativeTransformation);

            // Create the new bone
            var bone = new TreeBone();

            bone.ReferenceTransform        = childAbsoluteTransform;
            bone.InverseReferenceTransform = Matrix.Invert(bone.ReferenceTransform);
            bone.Length      = Vector3.Distance(fromLocation, targetLocation);
            bone.Rotation    = rotation;
            bone.ParentIndex = parent;
            bone.Stiffness   = skeleton.Branches[state.ParentIndex].StartRadius;
            // 1.0f; // TODO: Set stiffness according to radius
            bone.EndBranchIndex = state.ParentIndex;

            // Add the bone to the skeleton
            skeleton.Bones.Add(bone);

            // Set this bone as the parent
            int endIndex  = (state.ParentBoneIndex == -1 ? -1 : skeleton.Bones[state.ParentBoneIndex].EndBranchIndex);
            int boneIndex = state.ParentBoneIndex = skeleton.Bones.Count - 1;

            state.BoneLevel -= delta;

            // Update the bone index on branches
            int branchIndex = state.ParentIndex;

            while (branchIndex != endIndex)
            {
                TreeBranch branch = skeleton.Branches[branchIndex];
                branch.BoneIndex = boneIndex;
                skeleton.Branches[branchIndex] = branch;
                branchIndex = branch.ParentIndex;
            }
        }