/// <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; } }