예제 #1
0
        /*************************************************************************/
        private bool CheckValidity()
        {
            bool ret = true;

            for (int i = 0; i < m_LookAtBones.Length; i++)
            {
                PerfectLookAtData lookAtData = m_LookAtBones[i];
                if (lookAtData.m_Bone == null)
                {
                    ret = false;
                    break;
                }

                for (int j = 0; j < lookAtData.m_LinkedBones.Length; j++)
                {
                    if (lookAtData.m_LinkedBones[j].m_Bone == null)
                    {
                        ret = false;
                        break;
                    }
                }
            }

            return(ret);
        }
예제 #2
0
        /*************************************************************************/
        void Start()
        {
            m_gameObjectScale    = gameObject.transform.localScale;
            m_BlendedRotations   = new Quaternion[m_LookAtBones.Length];
            m_LastFrameRotations = new Quaternion[m_LookAtBones.Length];
            m_IsValid            = CheckValidity();

            for (int i = 0; i < m_LookAtBones.Length; i++)
            {
                PerfectLookAtData         lookAtBoneData     = m_LookAtBones[i];
                PerfecLookAtLinkedBones[] currentLinkedBones = lookAtBoneData.m_LinkedBones;
                lookAtBoneData.SetDefaultRotation(lookAtBoneData.m_Bone.localRotation);
                m_LastFrameRotations[i] = lookAtBoneData.m_Bone.localRotation;

                lookAtBoneData.CheckJointRotation();

                for (int j = 0; j < currentLinkedBones.Length; j++)
                {
                    currentLinkedBones[j].SetDefaultRotation(currentLinkedBones[j].m_Bone.localRotation);
                    currentLinkedBones[j].SetLastFrameRotation(currentLinkedBones[j].m_Bone.rotation);
                }
            }

            //Initialize Leg Bones for Leg IK.
            for (int i = 0; i < m_legStabilizers.Length; i++)
            {
                m_legStabilizers[i].Initialize();
            }
        }
예제 #3
0
        /*************************************************************************/
        private void CheckForForceDefaultRotation()
        {
            for (int i = 0; i < m_LookAtBones.Length; i++)
            {
                PerfectLookAtData lookAtData = m_LookAtBones[i];

                if (lookAtData.m_ResetToDefaultRotation)
                {
                    lookAtData.m_Bone.transform.localRotation = lookAtData.GetDefaultRotation();
                }

                for (int j = 0; j < lookAtData.m_LinkedBones.Length; j++)
                {
                    PerfecLookAtLinkedBones linkedBoneData = lookAtData.m_LinkedBones[j];
                    if (linkedBoneData.m_ResetToDefaultRotation)
                    {
                        linkedBoneData.m_Bone.transform.localRotation = linkedBoneData.GetDefaultRotation();
                    }
                }
            }
        }
예제 #4
0
        /*************************************************************************/
        void LateUpdate()
        {
            if (m_TargetObject == null)
            {
                Debug.LogWarning("No target object set for the component. Component won't work without a target object", this);
                return;
            }

            if (!m_IsValid)
            {
                Debug.LogWarning("Missing bones in PerfectlookAt component. Component won't work unless all bones are set", this);
                return;
            }

            if (m_Weight < Mathf.Epsilon)
            {
                //updating last frame rotation even if the weight is zero
                for (int i = 0; i < m_LookAtBones.Length; i++)
                {
                    PerfectLookAtData lookAtBoneData = m_LookAtBones[i];
                    m_LastFrameRotations[i] = lookAtBoneData.m_Bone.localRotation;

                    for (int j = 0; j < lookAtBoneData.m_LinkedBones.Length; j++)
                    {
                        lookAtBoneData.m_LinkedBones[j].SetLastFrameRotation(lookAtBoneData.m_LinkedBones[j].m_Bone.rotation);
                    }
                }

                return;
            }

            //Updating the bones rotations
            if (m_LookAtBones.Length > 0)
            {
                //if scale has changed the leg stabilizers get reinitialized
                CheckIfCharacterScaleChanged();

                CheckForForceDefaultRotation();

                //Cache Leg Bones for IK Leg Fix
                for (int i = 0; i < m_legStabilizers.Length; i++)
                {
                    m_legStabilizers[i].CacheBones();
                }

                Dictionary <int, Quaternion> linkedBonesRotations = new Dictionary <int, Quaternion>();
                Vector3 rotatedInitFwdVec = GetForwardVector(ref m_LookAtBones[0].m_Bone, m_LookAtBones[0].m_ForwardAxis);
                Vector3 currentFwdVec;
                Vector3 parentFwdVec;
                Vector3 targetVector = m_TargetObject.transform.position - m_LookAtBones[0].m_Bone.position;   //current vector is being updated in UpdateCurrentTargetVector
                Vector3 firstBoneRotatedInitFwdVec = rotatedInitFwdVec;
                byte    numBonesToRotate           = 1;

                for (int i = 0; i < m_LookAtBones.Length; i++)
                {
                    Transform currentBone = m_LookAtBones[i].m_Bone;
                    Transform parentBone  = currentBone.parent;;

                    float rotationLimit = m_LookAtBones[i].m_RotationLimit;
                    bool  parentExists  = true;

                    currentFwdVec = GetForwardVector(ref currentBone, m_LookAtBones[i].m_ForwardAxis);
                    parentFwdVec  = GetForwardVector(ref parentBone, m_LookAtBones[i].m_ParentBoneForwardAxis);

                    if (parentBone != null)
                    {
                        currentFwdVec = GetForwardVector(ref currentBone, m_LookAtBones[i].m_ForwardAxis);
                        parentFwdVec  = GetForwardVector(ref parentBone, m_LookAtBones[i].m_ParentBoneForwardAxis);
                        float diffAngleFromAnim = Vector3.Angle(currentFwdVec, parentFwdVec);

                        //in case animation already has a bone with relative rotation higher than the limit specified by user
                        if (diffAngleFromAnim > rotationLimit)
                        {
                            rotationLimit = diffAngleFromAnim;
                        }
                    }
                    else
                    {
                        parentExists = false;
                    }

                    Quaternion lookAtRot = GetWorldLookAtRotation(targetVector, rotatedInitFwdVec);

                    if (m_LookAtBones[i].m_RotateAroundUpVectorWeight > 0.0f)
                    {
                        Vector3 currentRotationAxis;
                        currentRotationAxis.x = lookAtRot.x;
                        currentRotationAxis.y = lookAtRot.y;
                        currentRotationAxis.z = lookAtRot.z;

                        //checking the up vector direction for rotation
                        float   rotationSign  = Mathf.Sign(Vector3.Cross(firstBoneRotatedInitFwdVec, targetVector).y);
                        Vector3 finalUpVector = rotationSign * m_UpVector;
                        finalUpVector = Vector3.Lerp(currentRotationAxis, finalUpVector, m_LookAtBones[i].m_RotateAroundUpVectorWeight);


                        lookAtRot = QuaternionFromAngleAxis(ref finalUpVector, GetAngleFromQuaternionRad(lookAtRot));
                    }

                    Quaternion childRotation = lookAtRot * currentBone.rotation;

                    if (parentExists)
                    {
                        //checking the angle difference
                        float diffAngle = Mathf.Abs(Vector3.Angle(parentFwdVec, lookAtRot * currentFwdVec)) - rotationLimit;
                        if (diffAngle > 0)
                        {
                            {
                                Vector3 rotationAxis  = new Vector3(lookAtRot.x, lookAtRot.y, lookAtRot.z);
                                float   limitAngleRad = GetAngleFromQuaternionRad(ref lookAtRot) + Mathf.Deg2Rad * (-diffAngle);

                                lookAtRot     = QuaternionFromAngleAxis(ref rotationAxis, limitAngleRad);
                                childRotation = lookAtRot * currentBone.rotation;

                                // blending with the rotation before assigning it to bone so it can have no effect on rotaiton limit checking
                                // and we can have updated bone position for calculating the rotated fwd vec and target vector
                                Quaternion currentBoneRotationLS = currentBone.localRotation;
                                m_LookAtBones[i].m_Bone.rotation = childRotation;
                                m_BlendedRotations[i]            = PerfectLookAtSlerp(currentBoneRotationLS, m_LookAtBones[i].m_Bone.localRotation, m_Weight);

                                if (m_LookAtBones[i].m_LinkedBones.Length > 0)
                                {
                                    linkedBonesRotations.Add(i, PerfectLookAtSlerp(Quaternion.identity, lookAtRot, m_Weight));
                                }
                            }

                            //
                            if (i != m_LookAtBones.Length - 1)
                            {
                                Vector3 currentBoneToParentPosDiff = m_LookAtBones[0].m_Bone.position - m_LookAtBones[i + 1].m_Bone.position;
                                Vector3 firstBoneToTargetDiff      = m_TargetObject.transform.position - m_LookAtBones[0].m_Bone.position;
                                rotatedInitFwdVec = GetForwardVector(ref m_LookAtBones[0].m_Bone, m_LookAtBones[0].m_ForwardAxis);
                                rotatedInitFwdVec.Normalize();
                                rotatedInitFwdVec = firstBoneToTargetDiff.magnitude * rotatedInitFwdVec;
                                rotatedInitFwdVec = currentBoneToParentPosDiff + rotatedInitFwdVec;

                                targetVector = currentBoneToParentPosDiff + firstBoneToTargetDiff;

                                numBonesToRotate++;

                                if (m_DrawDebugLookAtLines)
                                {
                                    Debug.DrawLine(m_LookAtBones[i + 1].m_Bone.position, m_LookAtBones[i + 1].m_Bone.position + rotatedInitFwdVec, Color.green);
                                    Debug.DrawLine(m_LookAtBones[i + 1].m_Bone.position, m_LookAtBones[i + 1].m_Bone.position + targetVector, Color.red);
                                }
                            }
                        }
                        else
                        {
                            Quaternion currentBoneRotationLS = currentBone.localRotation;
                            m_LookAtBones[i].m_Bone.rotation = childRotation;
                            m_BlendedRotations[i]            = PerfectLookAtSlerp(currentBoneRotationLS, m_LookAtBones[i].m_Bone.localRotation, m_Weight);

                            if (m_LookAtBones[i].m_LinkedBones.Length > 0)
                            {
                                linkedBonesRotations.Add(i, PerfectLookAtSlerp(Quaternion.identity, lookAtRot, m_Weight));
                            }

                            break;
                        }
                    }
                    else
                    {
                        Quaternion currentBoneRotationLS = currentBone.localRotation;
                        m_LookAtBones[i].m_Bone.rotation = childRotation;
                        m_BlendedRotations[i]            = PerfectLookAtSlerp(currentBoneRotationLS, m_LookAtBones[i].m_Bone.localRotation, m_Weight);

                        if (m_LookAtBones[i].m_LinkedBones.Length > 0)
                        {
                            linkedBonesRotations.Add(i, PerfectLookAtSlerp(Quaternion.identity, lookAtRot, m_Weight));
                        }

                        if (i < m_LookAtBones.Length - 1)
                        {
                            Debug.LogWarning("Warning Bone name doesn't have a parent. The rest of the PerfectLookAt bone chain won't work after this bone!", this);
                            break;
                        }
                    }
                }


                //Setting bones rotations final pass. The initial bone rotations are set during the last loop.
                //These two loops are used for blending and smooth movement.

                //Updating last frame rotations. Two loops are separated to have less jumps in memory and be more cache friendly.
                bool isBlending = Mathf.Abs(m_Weight - 1.0f) > Mathf.Epsilon;

                // Calculating the blend weight to blend between the current frame and last frame to achieve smooth rotations in dynamic animations with large range of movements.
                float smoothingWeight = Mathf.Clamp(m_LookAtBlendSpeed * Time.deltaTime, 0.0f, 1.0f);

                //Linearly blend the smoothingWeight to zero and its current frame value to be sure when perfect look at blend weight is zero-
                //the rotation is exactly the same as animation and no last frame is getting blended in.
                smoothingWeight = (smoothingWeight - 1.0f) * m_Weight + 1.0f;

                for (int k = 0; k < m_LookAtBones.Length; k++)
                {
                    PerfectLookAtData lookAtBoneData = m_LookAtBones[k];
                    Quaternion        boneLocalRotation;
                    if (isBlending && k < numBonesToRotate)
                    {
                        boneLocalRotation = m_BlendedRotations[k];
                    }
                    else
                    {
                        boneLocalRotation = lookAtBoneData.m_Bone.localRotation;
                    }

                    Quaternion localRotationFromAnim = lookAtBoneData.m_Bone.localRotation;

                    lookAtBoneData.m_Bone.localRotation = PerfectLookAtSlerp(m_LastFrameRotations[k], boneLocalRotation, smoothingWeight);

                    m_LastFrameRotations[k] = lookAtBoneData.m_Bone.localRotation;
                }

                // updating linked bones
                for (int m = 0; m < m_LookAtBones.Length; m++)
                {
                    PerfectLookAtData lookAtBoneData = m_LookAtBones[m];

                    if (lookAtBoneData.m_LinkedBones.Length > 0)
                    {
                        if (m < numBonesToRotate)
                        {
                            Quaternion linkedBoneLookAtQuat = linkedBonesRotations[m];
                            for (int n = 0; n < lookAtBoneData.m_LinkedBones.Length; n++)
                            {
                                Transform linkedBone = lookAtBoneData.m_LinkedBones[n].m_Bone;

                                linkedBone.rotation = PerfectLookAtSlerp(lookAtBoneData.m_LinkedBones[n].GetLastFrameRotation(),
                                                                         linkedBoneLookAtQuat * linkedBone.rotation, smoothingWeight);
                                lookAtBoneData.m_LinkedBones[n].SetLastFrameRotation(linkedBone.rotation);
                            }
                        }
                        else
                        {
                            for (int n = 0; n < lookAtBoneData.m_LinkedBones.Length; n++)
                            {
                                lookAtBoneData.m_LinkedBones[n].SetLastFrameRotation(lookAtBoneData.m_LinkedBones[n].m_Bone.rotation);
                            }
                        }
                    }
                }

                //Fix Leg Bones for IK Leg Fix
                for (int i = 0; i < m_legStabilizers.Length; i++)
                {
                    m_legStabilizers[i].FixLeg(LegStabilizerMaxIterations, m_LegStabilizerMinDistanceToStartSolving);
                }
            }
        }