private void UpdateDerivedValues() { // Validate chain. Compute bone lengths, bone indices and total chain length. if (_isDirty) { return; } _boneLengths.Clear(); _boneIndices.Clear(); _totalChainLength = -1; try { // Check if chain is valid. if (!SkeletonPose.IsAncestorOrSelf(RootBoneIndex, TipBoneIndex)) { throw new ArgumentException("The RootBoneIndex and the TipBoneIndex do not form a valid bone chain."); } // Get bone indices. SkeletonPose.GetChain(RootBoneIndex, TipBoneIndex, _boneIndices); var numberOfBones = _boneIndices.Count; // Get bone lengths. We compute the bone lengths from an actual bone pose because // our archer test model had a scale in the bone transforms. Therefore we cannot // compute the length from only the bind poses. _boneLengths.Capacity = numberOfBones; _totalChainLength = 0; for (int i = 0; i < numberOfBones - 1; i++) { int boneIndex = _boneIndices[i]; int childIndex = _boneIndices[i + 1]; var boneVector = SkeletonPose.GetBonePoseAbsolute(childIndex).Translation - SkeletonPose.GetBonePoseAbsolute(boneIndex).Translation; float boneLength = boneVector.Length; _boneLengths.Add(boneLength); _totalChainLength += boneLength; } // Tip bone. _boneLengths.Add((SkeletonPose.GetBonePoseAbsolute(TipBoneIndex).Scale *TipOffset).Length); _totalChainLength += _boneLengths[numberOfBones - 1]; // Initialize _bones list with dummy values. _bones.Clear(); for (int i = 0; i < numberOfBones; i++) { _bones.Add(SrtTransform.Identity); } _isDirty = true; } catch { _boneLengths.Clear(); _boneIndices.Clear(); _totalChainLength = 0; throw; } }