/// <summary> /// Allows the motor to process any specific bone logic after /// a bone has been added /// </summary> /// <param name="rIndex">Index position of the new bone</param> /// <param name="rBone">New bone that was added</param> public override void AddBone(BoneControllerBone rBone, bool rIncludeChildren) { base.AddBone(rBone, rIncludeChildren); RotationBone lBoneInfo = new RotationBone(); if (rBone != null) { lBoneInfo.Euler = (rBone._Transform.rotation * rBone._ToBoneForwardInv).eulerAngles; } _BoneInfo.Insert(mBones.IndexOf(rBone), lBoneInfo); }
/// <summary> /// Renders out bone details specific to the motor /// </summary> /// <param name="rIndex"></param> /// <param name="rBone"></param> /// <returns></returns> protected override bool RenderBone(int rIndex, BoneControllerBone rBone) { bool lIsDirty = false; #if UNITY_EDITOR while (rIndex >= _BoneInfo.Count) { RotationBone lBoneInfo = new RotationBone(); _BoneInfo.Insert(mBones.IndexOf(rBone), lBoneInfo); } float lNewWeight = EditorGUILayout.FloatField(new GUIContent("Motor Weight", "Determines how much the motor effects vs. currently animated rotation."), _BoneInfo[rIndex].Weight); if (lNewWeight != _BoneInfo[rIndex].Weight) { lIsDirty = true; _BoneInfo[rIndex].Weight = lNewWeight; } float lNewRotationLerp = EditorGUILayout.FloatField(new GUIContent("Rotation Lerp", "Determines how quickly we rotate to the target when using fixed updates."), _BoneInfo[rIndex].RotationLerp); if (lNewRotationLerp != _BoneInfo[rIndex].RotationLerp) { lIsDirty = true; _BoneInfo[rIndex].RotationLerp = lNewRotationLerp; } int lNewRotationAxis = EditorGUILayout.Popup("Rotation Space", _BoneInfo[rIndex].RotationAxis, EnumIKBoneRotationAxis.Names); if (lNewRotationAxis != _BoneInfo[rIndex].RotationAxis) { lIsDirty = true; _BoneInfo[rIndex].RotationAxis = lNewRotationAxis; } Vector3 lNewRotationSpeed = EditorGUILayout.Vector3Field(new GUIContent("Rotation Speed", "Degrees per second to rotate around the axis"), _BoneInfo[rIndex].RotationSpeed); if (lNewRotationSpeed != _BoneInfo[rIndex].RotationSpeed) { lIsDirty = true; _BoneInfo[rIndex].RotationSpeed = lNewRotationSpeed; } #endif return(lIsDirty); }
/// <summary> /// Process the motor each frame so that it can update the bone rotations. /// This is the function that should be overridden in each motor /// </summary> /// <param name="rDeltaTime">Delta time to use for the update</param> /// <param name="rUpdate">Determines if it is officially time to do the update</param> protected override void Update(float rDeltaTime, bool rUpdate) { if (mBones.Count == 0) { return; } // Process the motor info at start up if (!mIsInitialized) { // Ensure we have the correct amount of bone infos... we should while (_BoneInfo.Count < mBones.Count) { RotationBone lBoneInfo = new RotationBone(); _BoneInfo.Add(lBoneInfo); } // Initialize the euler angles that are our base for (int i = 0; i < mBones.Count; i++) { _BoneInfo[i].Euler = Vector3.zero; _BoneInfo[i].BaseRotation = mBones[i]._Transform.rotation; //_BoneInfo[i].Euler = mBones[i]._Transform.rotation.eulerAngles; } // Flag that we've initialized mIsInitialized = true; } // If it's time to update, determine the positions we need to be // at and lerp towards them. if (rUpdate) { // Process each bone for (int i = 0; i < mBones.Count; i++) { BoneControllerBone lBone = mBones[i]; RotationBone lBoneInfo = _BoneInfo[i]; // The current rotation we will lerp from. We remove the trailing rotation offset because we'll add it later Quaternion lCurrentRotation = lBone.Transform.rotation * lBone.ToBoneForward; // Rotation we're moving towards Quaternion lTargetRotation = lBone._Transform.rotation; // Speed this frame Vector3 lRotationSpeed = lBoneInfo.RotationSpeed * rDeltaTime; // Update the angles we're rotating to lBoneInfo.Euler += lRotationSpeed; // Rotate based on the axis if (lBoneInfo.RotationAxis == EnumIKBoneRotationAxis.BONE) { lTargetRotation = _BoneInfo[i].BaseRotation * Quaternion.Euler(lBoneInfo.Euler); } else if (lBoneInfo.RotationAxis == EnumIKBoneRotationAxis.MODEL) { lTargetRotation = _BoneInfo[i].BaseRotation * Quaternion.Euler(lBoneInfo.Euler) * lBone._ToBoneForward; } else { lTargetRotation = lTargetRotation * lBone._ToBoneForward; } // Rotation as determined by the target lBoneInfo.RotationTarget = Quaternion.Lerp(lCurrentRotation, lTargetRotation, _Weight * lBoneInfo.Weight); // Slowly move towards the rotation we determined lBoneInfo.Rotation = Quaternion.Lerp(lBoneInfo.Rotation, lBoneInfo.RotationTarget, (_IsFixedUpdateEnabled && !mIsFirstUpdate ? lBoneInfo.RotationLerp : 1f)); // Set the world rotation lBone.SetWorldRotation(lBoneInfo.Rotation, Quaternion.identity, _BoneWeight); } } // If it's not on a consistant update, we just want to reset the // last rotations that we found. else { for (int i = 0; i < mBones.Count; i++) { BoneControllerBone lBone = mBones[i]; if (lBone == null) { continue; } lBone.SetWorldRotation(_BoneInfo[i].Rotation, Quaternion.identity, _BoneWeight); } } }