/// <summary> /// Updates the absolute bone pose for the specified bone. /// </summary> /// <param name="boneIndex">The index of the bone.</param> private void UpdateBonePoseAbsolute(int boneIndex) { if (_isBonePoseAbsoluteDirty[boneIndex]) { lock (_syncRoot) { if (_isBonePoseAbsoluteDirty[boneIndex]) { // Make sure relative bone pose is up-to-date. UpdateBonePoseRelative(boneIndex); int parentIndex = _skeletonPose.Skeleton.GetParent(boneIndex); if (parentIndex < 0) { // No parent. _bonePoseAbsolute[boneIndex] = _bonePoseRelative[boneIndex]; } else { // Make sure parent is up-to-date. (Recursively update ancestors.) UpdateBonePoseAbsolute(parentIndex); //_bonePoseAbsolute[boneIndex] = _bonePoseAbsolute[parentIndex] * _bonePoseRelative[boneIndex]; SrtTransform.Multiply(ref _bonePoseAbsolute[parentIndex], ref _bonePoseRelative[boneIndex], out _bonePoseAbsolute[boneIndex]); } Thread.MemoryBarrier(); #else Interlocked.MemoryBarrier(); _isBonePoseAbsoluteDirty[boneIndex] = false; } } } }
/// <summary> /// Updates the relative bone pose for the specified bone. /// </summary> /// <param name="boneIndex">The index of the bone.</param> private void UpdateBonePoseRelative(int boneIndex) { if (_isBonePoseRelativeDirty[boneIndex]) { lock (_syncRoot) { if (_isBonePoseRelativeDirty[boneIndex]) { // _bonePoseRelative[boneIndex] = _skeletonPose.Skeleton.BindPosesRelative[boneIndex] * _skeletonPose.BoneTransforms[boneIndex]; SrtTransform.Multiply(ref _skeletonPose.Skeleton.BindPosesRelative[boneIndex], ref _skeletonPose.BoneTransforms[boneIndex], out _bonePoseRelative[boneIndex]); Thread.MemoryBarrier(); #else Interlocked.MemoryBarrier(); _isBonePoseRelativeDirty[boneIndex] = false; } } } }
/// <summary> /// Updates all bone transformations. /// </summary> public void Update() { // This method updates does not check the individual dirty flags. If something is // dirty all transforms are updated. Checking the dirty flags makes the average // case (whole skeleton is animated) a lot slower. if (_isDirty) { lock (_syncRoot) { if (_isDirty) { var skeleton = _skeletonPose.Skeleton; int numberOfBones = skeleton.NumberOfBones; // ----- Update dirty relative bone poses. var boneTransforms = _skeletonPose.BoneTransforms; var bindPosesRelative = skeleton.BindPosesRelative; for (int i = 0; i < numberOfBones; i++) { //_bonePoseRelative[i] = bindPosesRelative[i] * boneTransforms[i]; SrtTransform.Multiply(ref bindPosesRelative[i], ref boneTransforms[i], out _bonePoseRelative[i]); } // ----- Update dirty absolute bone poses. _bonePoseAbsolute[0] = _bonePoseRelative[0]; for (int i = 1; i < numberOfBones; i++) { int parentIndex = skeleton.GetParent(i); //_bonePoseAbsolute[i] = _bonePoseAbsolute[parentIndex] * _bonePoseRelative[i]; SrtTransform.Multiply(ref _bonePoseAbsolute[parentIndex], ref _bonePoseRelative[i], out _bonePoseAbsolute[i]); } // ----- Update skinning matrices (either the Matrix or the XNA variant). if (_skinningMatrices != null) { for (int i = 0; i < numberOfBones; i++) { //_skinningMatrices[i] = _bonePoseAbsolute[i] * skeleton.BindPosesAbsoluteInverse[i]; SrtTransform.Multiply(ref _bonePoseAbsolute[i], ref skeleton.BindPosesAbsoluteInverse[i], out _skinningMatrices[i]); } } if (_skinningMatricesXna != null) { if (_skinningMatrices != null) { for (int i = 0; i < numberOfBones; i++) _skinningMatricesXna[i] = (Matrix)_skinningMatrices[i]; } else { for (int i = 0; i < numberOfBones; i++) { //_skinningMatricesXna[i] = _bonePoseAbsolute[i] * skeleton.BindPosesAbsoluteInverse[i]; SrtTransform.Multiply(ref _bonePoseAbsolute[i], ref skeleton.BindPosesAbsoluteInverse[i], out _skinningMatricesXna[i]); } } } Thread.MemoryBarrier(); #else Interlocked.MemoryBarrier(); _isBonePoseRelativeDirty.SetAll(false); _isBonePoseAbsoluteDirty.SetAll(false); _isSkinningMatrixDirty.SetAll(false); _isDirty = false; } } } }
/// <summary> /// Initializes the skeleton. /// </summary> /// <param name="boneParents">The bone parents.</param> /// <param name="boneNames">The bone names.</param> /// <param name="bindPosesRelative">The bind poses.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="boneParents"/>, <paramref name="boneNames"/> or /// <paramref name="bindPosesRelative"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// Either the given lists are empty, have different length, or the /// <paramref name="boneParents"/> are invalid (parent bones must come be before their child /// bones). /// </exception> internal void Initialize(IList <int> boneParents, IList <string> boneNames, IList <SrtTransform> bindPosesRelative) { if (boneParents == null) { throw new ArgumentNullException("boneParents"); } if (boneNames == null) { throw new ArgumentNullException("boneNames"); } if (bindPosesRelative == null) { throw new ArgumentNullException("bindPosesRelative"); } var numberOfBones = boneParents.Count; if (numberOfBones == 0) { throw new ArgumentException("boneParents list must not be empty."); } if (boneNames.Count == 0) { throw new ArgumentException("boneNames list must not be empty."); } if (bindPosesRelative.Count == 0) { throw new ArgumentException("bindPosesRelative list must not be empty."); } if (numberOfBones != boneNames.Count || numberOfBones != bindPosesRelative.Count) { throw new ArgumentException("The lists must have the same number of elements."); } // Check if bone parents come before children. This ordering also forbids cycles. for (int index = 0; index < numberOfBones; index++) { var parentIndex = boneParents[index]; if (parentIndex >= index) { throw new ArgumentException("Invalid boneParents list. Parent bones must have a lower index than child bones."); } } // Build list of bone nodes. Bones = new Bone[numberOfBones]; var children = new List <int>(); for (int index = 0; index < numberOfBones; index++) { Bone bone = new Bone(); // Set parent index. int parentIndex = boneParents[index]; if (parentIndex < -1) { parentIndex = -1; } bone.Parent = parentIndex; // Create array of child indices. children.Clear(); for (int childIndex = index + 1; childIndex < numberOfBones; childIndex++) { if (boneParents[childIndex] == index) { children.Add(childIndex); } } if (children.Count > 0) { bone.Children = children.ToArray(); } Bones[index] = bone; } // Initialize bone name/index dictionary. if (BoneNames == null) { BoneNames = new Dictionary <string, int>(numberOfBones); } else { BoneNames.Clear(); } for (int index = 0; index < numberOfBones; index++) { var name = boneNames[index]; if (name != null) { BoneNames[name] = index; } } // Copy relative bind poses. if (BindPosesRelative == null) { BindPosesRelative = new SrtTransform[numberOfBones]; } for (int index = 0; index < numberOfBones; index++) { BindPosesRelative[index] = bindPosesRelative[index]; } // Initialize absolute bind poses (inverse). if (BindPosesAbsoluteInverse == null) { BindPosesAbsoluteInverse = new SrtTransform[numberOfBones]; } // First store the non-inverted BindTransforms in model space. BindPosesAbsoluteInverse[0] = BindPosesRelative[0]; for (int index = 1; index < numberOfBones; index++) { var parentIndex = Bones[index].Parent; //BindPosesAbsoluteInverse[index] = BindPosesAbsoluteInverse[parentIndex] * BindPosesRelative[index]; SrtTransform.Multiply(ref BindPosesAbsoluteInverse[parentIndex], ref BindPosesRelative[index], out BindPosesAbsoluteInverse[index]); } // Invert matrices. for (int index = 0; index < numberOfBones; index++) { BindPosesAbsoluteInverse[index].Invert(); } }