_ResetCustomEyes() 공개 메소드

public _ResetCustomEyes ( ) : void
리턴 void
예제 #1
0
            public bool Solve(FullBodyIK fullBodyIK)
            {
                if (_neckBone == null || !_neckBone.transformIsAlive ||
                    _headBone == null || !_headBone.transformIsAlive ||
                    _headBone.parentBone == null || !_headBone.parentBone.transformIsAlive)
                {
                    return(false);
                }

                _SyncDisplacement(fullBodyIK);

                float headPositionWeight = _headEffector.positionEnabled ? _headEffector.positionWeight : 0.0f;
                float eyesPositionWeight = _eyesEffector.positionEnabled ? _eyesEffector.positionWeight : 0.0f;

                if (headPositionWeight <= IKEpsilon && eyesPositionWeight <= IKEpsilon)
                {
                    Quaternion parentWorldRotation = _neckBone.parentBone.worldRotation;
                    Quaternion parentBaseRotation;
                    SAFBIKQuatMult(out parentBaseRotation, ref parentWorldRotation, ref _neckBone.parentBone._worldToBaseRotation);

                    if (_internalValues.resetTransforms)
                    {
                        Quaternion tempRotation;
                        SAFBIKQuatMult(out tempRotation, ref parentBaseRotation, ref _neckBone._baseToWorldRotation);
                        _neckBone.worldRotation = tempRotation;
                    }

                    float headRotationWeight = _headEffector.rotationEnabled ? _headEffector.rotationWeight : 0.0f;
                    if (headRotationWeight > IKEpsilon)
                    {
                        Quaternion headEffectorWorldRotation = _headEffector.worldRotation;
                        Quaternion toRotation;
                        SAFBIKQuatMult(out toRotation, ref headEffectorWorldRotation, ref _headEffectorToWorldRotation);
                        if (headRotationWeight < 1.0f - IKEpsilon)
                        {
                            Quaternion fromRotation;
                            if (_internalValues.resetTransforms)
                            {
                                SAFBIKQuatMult(out fromRotation, ref parentBaseRotation, ref _headBone._baseToWorldRotation);
                            }
                            else
                            {
                                fromRotation = _headBone.worldRotation;                                 // This is able to use _headBone.worldRotation directly.
                            }
                            _headBone.worldRotation = Quaternion.Lerp(fromRotation, toRotation, headRotationWeight);
                        }
                        else
                        {
                            _headBone.worldRotation = toRotation;
                        }

                        _HeadRotationLimit();
                    }
                    else
                    {
                        if (_internalValues.resetTransforms)
                        {
                            Quaternion tempRotation;
                            SAFBIKQuatMult(out tempRotation, ref parentBaseRotation, ref _headBone._baseToWorldRotation);
                            _headBone.worldRotation = tempRotation;
                        }
                    }

                    if (_internalValues.resetTransforms)
                    {
                        if (_isEnabledCustomEyes)
                        {
                            fullBodyIK._ResetCustomEyes();
                        }
                        else
                        {
                            _ResetEyes();
                        }
                    }

                    return(_internalValues.resetTransforms || (headRotationWeight > IKEpsilon));
                }

                _Solve(fullBodyIK);
                return(true);
            }
예제 #2
0
			public bool Solve( FullBodyIK fullBodyIK )
			{
				if( _neckBone == null || !_neckBone.transformIsAlive ||
					_headBone == null || !_headBone.transformIsAlive ||
					_headBone.parentBone == null || !_headBone.parentBone.transformIsAlive ) {
					return false;
				}

				_SyncDisplacement( fullBodyIK );

				float headPositionWeight = _headEffector.positionEnabled ? _headEffector.positionWeight : 0.0f;
				float eyesPositionWeight = _eyesEffector.positionEnabled ? _eyesEffector.positionWeight : 0.0f;

				if( headPositionWeight <= IKEpsilon && eyesPositionWeight <= IKEpsilon ) {
					Quaternion parentWorldRotation = _neckBone.parentBone.worldRotation;
					Quaternion parentBaseRotation;
					SAFBIKQuatMult( out parentBaseRotation, ref parentWorldRotation, ref _neckBone.parentBone._worldToBaseRotation );

					if( _internalValues.resetTransforms ) {
						Quaternion tempRotation;
						SAFBIKQuatMult( out tempRotation, ref parentBaseRotation, ref _neckBone._baseToWorldRotation );
						_neckBone.worldRotation = tempRotation;
					}

					float headRotationWeight = _headEffector.rotationEnabled ? _headEffector.rotationWeight : 0.0f;
					if( headRotationWeight > IKEpsilon ) {
						Quaternion headEffectorWorldRotation = _headEffector.worldRotation;
                        Quaternion toRotation;
						SAFBIKQuatMult( out toRotation, ref headEffectorWorldRotation, ref _headEffectorToWorldRotation );
						if( headRotationWeight < 1.0f - IKEpsilon ) {
							Quaternion fromRotation;
							if( _internalValues.resetTransforms ) {
								SAFBIKQuatMult( out fromRotation, ref parentBaseRotation, ref _headBone._baseToWorldRotation );
                            } else {
								fromRotation = _headBone.worldRotation; // This is able to use _headBone.worldRotation directly.
							}
							_headBone.worldRotation = Quaternion.Lerp( fromRotation, toRotation, headRotationWeight );
						} else {
							_headBone.worldRotation = toRotation;
						}

						_HeadRotationLimit();
					} else {
						if( _internalValues.resetTransforms ) {
							Quaternion tempRotation;
							SAFBIKQuatMult( out tempRotation, ref parentBaseRotation, ref _headBone._baseToWorldRotation );
							_headBone.worldRotation = tempRotation;
                        }
					}

					if( _internalValues.resetTransforms ) {
						if( _isEnabledCustomEyes ) {
							fullBodyIK._ResetCustomEyes();
						} else {
							_ResetEyes();
						}
					}

					return _internalValues.resetTransforms || (headRotationWeight > IKEpsilon);
				}

				_Solve( fullBodyIK );
				return true;
			}
예제 #3
0
            void _Solve(FullBodyIK fullBodyIK)
            {
                Quaternion parentWorldRotation = _neckBone.parentBone.worldRotation;
                Matrix3x3  parentBasis;

                SAFBIKMatSetRotMultInv1(out parentBasis, ref parentWorldRotation, ref _neckBone.parentBone._defaultRotation);
                Matrix3x3 parentBaseBasis;

                SAFBIKMatMult(out parentBaseBasis, ref parentBasis, ref _internalValues.defaultRootBasis);
                Quaternion parentBaseRotation;

                SAFBIKQuatMult(out parentBaseRotation, ref parentWorldRotation, ref _neckBone.parentBone._worldToBaseRotation);

                float headPositionWeight = _headEffector.positionEnabled ? _headEffector.positionWeight : 0.0f;
                float eyesPositionWeight = _eyesEffector.positionEnabled ? _eyesEffector.positionWeight : 0.0f;

                Quaternion neckBonePrevRotation     = Quaternion.identity;
                Quaternion headBonePrevRotation     = Quaternion.identity;
                Quaternion leftEyeBonePrevRotation  = Quaternion.identity;
                Quaternion rightEyeBonePrevRotation = Quaternion.identity;

                if (!_internalValues.resetTransforms)
                {
                    neckBonePrevRotation = _neckBone.worldRotation;
                    headBonePrevRotation = _headBone.worldRotation;
                    if (_leftEyeBone != null && _leftEyeBone.transformIsAlive)
                    {
                        leftEyeBonePrevRotation = _leftEyeBone.worldRotation;
                    }
                    if (_rightEyeBone != null && _rightEyeBone.transformIsAlive)
                    {
                        rightEyeBonePrevRotation = _rightEyeBone.worldRotation;
                    }
                }

                // for Neck
                if (headPositionWeight > IKEpsilon)
                {
                    Matrix3x3 neckBoneBasis;
                    SAFBIKMatMult(out neckBoneBasis, ref parentBasis, ref _neckBone._localAxisBasis);

                    Vector3 yDir = _headEffector.worldPosition - _neckBone.worldPosition;                     // Not use _hidden_worldPosition
                    if (SAFBIKVecNormalize(ref yDir))
                    {
                        Vector3 localDir;
                        SAFBIKMatMultVecInv(out localDir, ref neckBoneBasis, ref yDir);

                        if (_LimitXZ_Square(ref localDir,
                                            _internalValues.headIK.neckLimitRollTheta.sin,
                                            _internalValues.headIK.neckLimitRollTheta.sin,
                                            _internalValues.headIK.neckLimitPitchDownTheta.sin,
                                            _internalValues.headIK.neckLimitPitchUpTheta.sin))
                        {
                            SAFBIKMatMultVec(out yDir, ref neckBoneBasis, ref localDir);
                        }

                        Vector3 xDir = parentBaseBasis.column0;
                        Vector3 zDir = parentBaseBasis.column2;
                        if (SAFBIKComputeBasisLockY(out neckBoneBasis, ref xDir, ref yDir, ref zDir))
                        {
                            Quaternion worldRotation;
                            SAFBIKMatMultGetRot(out worldRotation, ref neckBoneBasis, ref _neckBone._boneToWorldBasis);
                            if (headPositionWeight < 1.0f - IKEpsilon)
                            {
                                Quaternion fromRotation;
                                if (_internalValues.resetTransforms)
                                {
                                    SAFBIKQuatMult(out fromRotation, ref parentBaseRotation, ref _neckBone._baseToWorldRotation);
                                }
                                else
                                {
                                    fromRotation = neckBonePrevRotation;                                     // This is able to use _headBone.worldRotation directly.
                                }

                                _neckBone.worldRotation = Quaternion.Lerp(fromRotation, worldRotation, headPositionWeight);
                            }
                            else
                            {
                                _neckBone.worldRotation = worldRotation;
                            }
                        }
                    }
                }
                else if (_internalValues.resetTransforms)
                {
                    Quaternion tempRotation;
                    SAFBIKQuatMult(out tempRotation, ref parentBaseRotation, ref _neckBone._baseToWorldRotation);
                    _neckBone.worldRotation = tempRotation;
                }

                // for Head / Eyes
                if (eyesPositionWeight <= IKEpsilon)
                {
                    float headRotationWeight = _headEffector.rotationEnabled ? _headEffector.rotationWeight : 0.0f;
                    if (headRotationWeight > IKEpsilon)
                    {
                        Quaternion headEffectorWorldRotation = _headEffector.worldRotation;
                        Quaternion toRotation;
                        SAFBIKQuatMult(out toRotation, ref headEffectorWorldRotation, ref _headEffectorToWorldRotation);
                        if (headRotationWeight < 1.0f - IKEpsilon)
                        {
                            Quaternion fromRotation;
                            Quaternion neckBoneWorldRotation = _neckBone.worldRotation;
                            if (_internalValues.resetTransforms)
                            {
                                SAFBIKQuatMult3(out fromRotation, ref neckBoneWorldRotation, ref _neckBone._worldToBaseRotation, ref _headBone._baseToWorldRotation);
                            }
                            else
                            {
                                // Not use _headBone.worldRotation.
                                SAFBIKQuatMultNorm3Inv1(out fromRotation, ref neckBoneWorldRotation, ref neckBonePrevRotation, ref headBonePrevRotation);
                            }
                            _headBone.worldRotation = Quaternion.Lerp(fromRotation, toRotation, headRotationWeight);
                        }
                        else
                        {
                            _headBone.worldRotation = toRotation;
                        }
                    }
                    else
                    {
                        if (_internalValues.resetTransforms)
                        {
                            Quaternion neckBoneWorldRotation = _neckBone.worldRotation;
                            Quaternion headBoneWorldRotation;
                            SAFBIKQuatMult3(out headBoneWorldRotation, ref neckBoneWorldRotation, ref _neckBone._worldToBaseRotation, ref _headBone._baseToWorldRotation);
                            _headBone.worldRotation = headBoneWorldRotation;
                        }
                    }

                    _HeadRotationLimit();

                    if (_internalValues.resetTransforms)
                    {
                        if (_isEnabledCustomEyes)
                        {
                            fullBodyIK._ResetCustomEyes();
                        }
                        else
                        {
                            _ResetEyes();
                        }
                    }

                    return;
                }

                {
                    Vector3 eyesPosition, parentBoneWorldPosition = _neckBone.parentBone.worldPosition;
                    SAFBIKMatMultVecPreSubAdd(out eyesPosition, ref parentBasis, ref _eyesEffector._defaultPosition, ref _neckBone.parentBone._defaultPosition, ref parentBoneWorldPosition);

                    // Note: Not use _eyesEffector._hidden_worldPosition
                    Vector3 eyesDir = _eyesEffector.worldPosition - eyesPosition;                     // Memo: Not normalize yet.

                    Matrix3x3 neckBaseBasis = parentBaseBasis;

                    {
                        Vector3 localDir;
                        SAFBIKMatMultVecInv(out localDir, ref parentBaseBasis, ref eyesDir);

                        localDir.y *= _settings.headIK.eyesToNeckPitchRate;
                        SAFBIKVecNormalize(ref localDir);

                        if (_ComputeEyesRange(ref localDir, _internalValues.headIK.eyesTraceTheta.cos))
                        {
                            if (localDir.y < -_internalValues.headIK.neckLimitPitchDownTheta.sin)
                            {
                                localDir.y = -_internalValues.headIK.neckLimitPitchDownTheta.sin;
                            }
                            else if (localDir.y > _internalValues.headIK.neckLimitPitchUpTheta.sin)
                            {
                                localDir.y = _internalValues.headIK.neckLimitPitchUpTheta.sin;
                            }
                            localDir.x = 0.0f;
                            localDir.z = SAFBIKSqrt(1.0f - localDir.y * localDir.y);
                        }

                        SAFBIKMatMultVec(out eyesDir, ref parentBaseBasis, ref localDir);

                        {
                            Vector3 xDir = parentBaseBasis.column0;
                            Vector3 yDir = parentBaseBasis.column1;
                            Vector3 zDir = eyesDir;

                            if (!SAFBIKComputeBasisLockZ(out neckBaseBasis, ref xDir, ref yDir, ref zDir))
                            {
                                neckBaseBasis = parentBaseBasis;                                 // Failsafe.
                            }
                        }

                        Quaternion worldRotation;
                        SAFBIKMatMultGetRot(out worldRotation, ref neckBaseBasis, ref _neckBone._baseToWorldBasis);
                        if (_eyesEffector.positionWeight < 1.0f - IKEpsilon)
                        {
                            Quaternion neckWorldRotation = Quaternion.Lerp(_neckBone.worldRotation, worldRotation, _eyesEffector.positionWeight);                               // This is able to use _neckBone.worldRotation directly.
                            _neckBone.worldRotation = neckWorldRotation;
                            SAFBIKMatSetRotMult(out neckBaseBasis, ref neckWorldRotation, ref _neckBone._worldToBaseRotation);
                        }
                        else
                        {
                            _neckBone.worldRotation = worldRotation;
                        }
                    }

                    Matrix3x3 neckBasis;
                    SAFBIKMatMult(out neckBasis, ref neckBaseBasis, ref _internalValues.defaultRootBasisInv);

                    Vector3 neckBoneWorldPosition = _neckBone.worldPosition;
                    SAFBIKMatMultVecPreSubAdd(out eyesPosition, ref neckBasis, ref _eyesEffector._defaultPosition, ref _neckBone._defaultPosition, ref neckBoneWorldPosition);

                    // Note: Not use _eyesEffector._hidden_worldPosition
                    eyesDir = _eyesEffector.worldPosition - eyesPosition;

                    Matrix3x3 headBaseBasis = neckBaseBasis;

                    {
                        Vector3 localDir;
                        SAFBIKMatMultVecInv(out localDir, ref neckBaseBasis, ref eyesDir);

                        localDir.x *= _settings.headIK.eyesToHeadYawRate;
                        localDir.y *= _settings.headIK.eyesToHeadPitchRate;

                        SAFBIKVecNormalize(ref localDir);

                        if (_ComputeEyesRange(ref localDir, _internalValues.headIK.eyesTraceTheta.cos))
                        {
                            // Note: Not use _LimitXY() for Stability
                            _LimitXY_Square(ref localDir,
                                            _internalValues.headIK.headLimitYawTheta.sin,
                                            _internalValues.headIK.headLimitYawTheta.sin,
                                            _internalValues.headIK.headLimitPitchDownTheta.sin,
                                            _internalValues.headIK.headLimitPitchUpTheta.sin);
                        }

                        SAFBIKMatMultVec(out eyesDir, ref neckBaseBasis, ref localDir);

                        {
                            Vector3 xDir = neckBaseBasis.column0;
                            Vector3 yDir = neckBaseBasis.column1;
                            Vector3 zDir = eyesDir;

                            if (!SAFBIKComputeBasisLockZ(out headBaseBasis, ref xDir, ref yDir, ref zDir))
                            {
                                headBaseBasis = neckBaseBasis;
                            }
                        }

                        Quaternion worldRotation;
                        SAFBIKMatMultGetRot(out worldRotation, ref headBaseBasis, ref _headBone._baseToWorldBasis);
                        if (_eyesEffector.positionWeight < 1.0f - IKEpsilon)
                        {
                            Quaternion neckBoneWorldRotation = _neckBone.worldRotation;
                            Quaternion headFromWorldRotation;
                            SAFBIKQuatMultNorm3Inv1(out headFromWorldRotation, ref neckBoneWorldRotation, ref neckBonePrevRotation, ref headBonePrevRotation);
                            Quaternion headWorldRotation = Quaternion.Lerp(headFromWorldRotation, worldRotation, _eyesEffector.positionWeight);
                            _headBone.worldRotation = headWorldRotation;
                            SAFBIKMatSetRotMult(out headBaseBasis, ref headWorldRotation, ref _headBone._worldToBaseRotation);
                        }
                        else
                        {
                            _headBone.worldRotation = worldRotation;
                        }
                    }

                    Matrix3x3 headBasis;
                    SAFBIKMatMult(out headBasis, ref headBaseBasis, ref _internalValues.defaultRootBasisInv);

                    if (_isEnabledCustomEyes)
                    {
                        fullBodyIK._SolveCustomEyes(ref neckBasis, ref headBasis, ref headBaseBasis);
                    }
                    else
                    {
                        _SolveEyes(ref neckBasis, ref headBasis, ref headBaseBasis, ref headBonePrevRotation, ref leftEyeBonePrevRotation, ref rightEyeBonePrevRotation);
                    }
                }
            }
예제 #4
0
			void _Solve( FullBodyIK fullBodyIK )
			{
				Quaternion parentWorldRotation = _neckBone.parentBone.worldRotation;
				Matrix3x3 parentBasis;
				SAFBIKMatSetRotMultInv1( out parentBasis, ref parentWorldRotation, ref _neckBone.parentBone._defaultRotation );
				Matrix3x3 parentBaseBasis;
				SAFBIKMatMult( out parentBaseBasis, ref parentBasis, ref _internalValues.defaultRootBasis );
				Quaternion parentBaseRotation;
				SAFBIKQuatMult( out parentBaseRotation, ref parentWorldRotation, ref _neckBone.parentBone._worldToBaseRotation );

				float headPositionWeight = _headEffector.positionEnabled ? _headEffector.positionWeight : 0.0f;
				float eyesPositionWeight = _eyesEffector.positionEnabled ? _eyesEffector.positionWeight : 0.0f;

				Quaternion neckBonePrevRotation = Quaternion.identity;
				Quaternion headBonePrevRotation = Quaternion.identity;
				Quaternion leftEyeBonePrevRotation = Quaternion.identity;
				Quaternion rightEyeBonePrevRotation = Quaternion.identity;
				if( !_internalValues.resetTransforms ) {
					neckBonePrevRotation = _neckBone.worldRotation;
					headBonePrevRotation = _headBone.worldRotation;
					if( _leftEyeBone != null && _leftEyeBone.transformIsAlive ) {
						leftEyeBonePrevRotation = _leftEyeBone.worldRotation;
					}
					if( _rightEyeBone != null && _rightEyeBone.transformIsAlive ) {
						rightEyeBonePrevRotation = _rightEyeBone.worldRotation;
					}
				}

				// for Neck
				if( headPositionWeight > IKEpsilon ) {
					Matrix3x3 neckBoneBasis;
					SAFBIKMatMult( out neckBoneBasis, ref parentBasis, ref _neckBone._localAxisBasis );

					Vector3 yDir = _headEffector.worldPosition - _neckBone.worldPosition; // Not use _hidden_worldPosition
					if( SAFBIKVecNormalize( ref yDir ) ) {
						Vector3 localDir;
						SAFBIKMatMultVecInv( out localDir, ref neckBoneBasis, ref yDir );

						if( _LimitXZ_Square( ref localDir,
							_internalValues.headIK.neckLimitRollTheta.sin,
							_internalValues.headIK.neckLimitRollTheta.sin,
							_internalValues.headIK.neckLimitPitchDownTheta.sin,
							_internalValues.headIK.neckLimitPitchUpTheta.sin ) ) {
							SAFBIKMatMultVec( out yDir, ref neckBoneBasis, ref localDir );
						}

						Vector3 xDir = parentBaseBasis.column0;
						Vector3 zDir = parentBaseBasis.column2;
						if( SAFBIKComputeBasisLockY( out neckBoneBasis, ref xDir, ref yDir, ref zDir ) ) {
							Quaternion worldRotation;
							SAFBIKMatMultGetRot( out worldRotation, ref neckBoneBasis, ref _neckBone._boneToWorldBasis );
							if( headPositionWeight < 1.0f - IKEpsilon ) {
								Quaternion fromRotation;
								if( _internalValues.resetTransforms ) {
									SAFBIKQuatMult( out fromRotation, ref parentBaseRotation, ref _neckBone._baseToWorldRotation );
								} else {
									fromRotation = neckBonePrevRotation; // This is able to use _headBone.worldRotation directly.
								}

								_neckBone.worldRotation = Quaternion.Lerp( fromRotation, worldRotation, headPositionWeight );
                            } else {
								_neckBone.worldRotation = worldRotation;
							}
						}
					}
				} else if( _internalValues.resetTransforms ) {
					Quaternion tempRotation;
					SAFBIKQuatMult( out tempRotation, ref parentBaseRotation, ref _neckBone._baseToWorldRotation );
					_neckBone.worldRotation = tempRotation;
				}

				// for Head / Eyes
				if( eyesPositionWeight <= IKEpsilon ) {
					float headRotationWeight = _headEffector.rotationEnabled ? _headEffector.rotationWeight : 0.0f;
					if( headRotationWeight > IKEpsilon ) {
						Quaternion headEffectorWorldRotation = _headEffector.worldRotation;
						Quaternion toRotation;
						SAFBIKQuatMult( out toRotation, ref headEffectorWorldRotation, ref _headEffectorToWorldRotation );
						if( headRotationWeight < 1.0f - IKEpsilon ) {
							Quaternion fromRotation;
							Quaternion neckBoneWorldRotation = _neckBone.worldRotation;
							if( _internalValues.resetTransforms ) {
								SAFBIKQuatMult3( out fromRotation, ref neckBoneWorldRotation, ref _neckBone._worldToBaseRotation, ref _headBone._baseToWorldRotation );
							} else {
								// Not use _headBone.worldRotation.
								SAFBIKQuatMultNorm3Inv1( out fromRotation, ref neckBoneWorldRotation, ref neckBonePrevRotation, ref headBonePrevRotation );
							}
							_headBone.worldRotation = Quaternion.Lerp( fromRotation, toRotation, headRotationWeight );
						} else {
							_headBone.worldRotation = toRotation;
						}
					} else {
						if( _internalValues.resetTransforms ) {
							Quaternion neckBoneWorldRotation = _neckBone.worldRotation;
							Quaternion headBoneWorldRotation;
							SAFBIKQuatMult3( out headBoneWorldRotation, ref neckBoneWorldRotation, ref _neckBone._worldToBaseRotation, ref _headBone._baseToWorldRotation );
							_headBone.worldRotation = headBoneWorldRotation;
                        }
					}

					_HeadRotationLimit();

					if( _internalValues.resetTransforms ) {
						if( _isEnabledCustomEyes ) {
							fullBodyIK._ResetCustomEyes();
						} else {
							_ResetEyes();
						}
					}

					return;
				}

				{
					Vector3 eyesPosition, parentBoneWorldPosition = _neckBone.parentBone.worldPosition;
					SAFBIKMatMultVecPreSubAdd( out eyesPosition, ref parentBasis, ref _eyesEffector._defaultPosition, ref _neckBone.parentBone._defaultPosition, ref parentBoneWorldPosition );

					// Note: Not use _eyesEffector._hidden_worldPosition
					Vector3 eyesDir = _eyesEffector.worldPosition - eyesPosition; // Memo: Not normalize yet.

					Matrix3x3 neckBaseBasis = parentBaseBasis;

					{
						Vector3 localDir;
						SAFBIKMatMultVecInv( out localDir, ref parentBaseBasis, ref eyesDir );

						localDir.y *= _settings.headIK.eyesToNeckPitchRate;
						SAFBIKVecNormalize( ref localDir );

						if( _ComputeEyesRange( ref localDir, _internalValues.headIK.eyesTraceTheta.cos ) ) {
							if( localDir.y < -_internalValues.headIK.neckLimitPitchDownTheta.sin ) {
								localDir.y = -_internalValues.headIK.neckLimitPitchDownTheta.sin;
							} else if( localDir.y > _internalValues.headIK.neckLimitPitchUpTheta.sin ) {
								localDir.y = _internalValues.headIK.neckLimitPitchUpTheta.sin;
							}
							localDir.x = 0.0f;
							localDir.z = SAFBIKSqrt( 1.0f - localDir.y * localDir.y );
						}

						SAFBIKMatMultVec( out eyesDir, ref parentBaseBasis, ref localDir );

						{
							Vector3 xDir = parentBaseBasis.column0;
							Vector3 yDir = parentBaseBasis.column1;
							Vector3 zDir = eyesDir;

							if( !SAFBIKComputeBasisLockZ( out neckBaseBasis, ref xDir, ref yDir, ref zDir ) ) {
								neckBaseBasis = parentBaseBasis; // Failsafe.
                            }
						}

						Quaternion worldRotation;
						SAFBIKMatMultGetRot( out worldRotation, ref neckBaseBasis, ref _neckBone._baseToWorldBasis );
						if( _eyesEffector.positionWeight < 1.0f - IKEpsilon ) {
							Quaternion neckWorldRotation = Quaternion.Lerp( _neckBone.worldRotation, worldRotation, _eyesEffector.positionWeight ); // This is able to use _neckBone.worldRotation directly.
							_neckBone.worldRotation = neckWorldRotation;
                            SAFBIKMatSetRotMult( out neckBaseBasis, ref neckWorldRotation, ref _neckBone._worldToBaseRotation );
						} else {
							_neckBone.worldRotation = worldRotation;
						}
                    }

					Matrix3x3 neckBasis;
					SAFBIKMatMult( out neckBasis, ref neckBaseBasis, ref _internalValues.defaultRootBasisInv );

					Vector3 neckBoneWorldPosition = _neckBone.worldPosition;
                    SAFBIKMatMultVecPreSubAdd( out eyesPosition, ref neckBasis, ref _eyesEffector._defaultPosition, ref _neckBone._defaultPosition, ref neckBoneWorldPosition );

					// Note: Not use _eyesEffector._hidden_worldPosition
					eyesDir = _eyesEffector.worldPosition - eyesPosition;

					Matrix3x3 headBaseBasis = neckBaseBasis;

					{
						Vector3 localDir;
						SAFBIKMatMultVecInv( out localDir, ref neckBaseBasis, ref eyesDir );

						localDir.x *= _settings.headIK.eyesToHeadYawRate;
						localDir.y *= _settings.headIK.eyesToHeadPitchRate;

						SAFBIKVecNormalize( ref localDir );

						if( _ComputeEyesRange( ref localDir, _internalValues.headIK.eyesTraceTheta.cos ) ) {
							// Note: Not use _LimitXY() for Stability
							_LimitXY_Square( ref localDir,
								_internalValues.headIK.headLimitYawTheta.sin,
								_internalValues.headIK.headLimitYawTheta.sin,
								_internalValues.headIK.headLimitPitchDownTheta.sin,
								_internalValues.headIK.headLimitPitchUpTheta.sin );
						}
						
						SAFBIKMatMultVec( out eyesDir, ref neckBaseBasis, ref localDir );

						{
							Vector3 xDir = neckBaseBasis.column0;
							Vector3 yDir = neckBaseBasis.column1;
							Vector3 zDir = eyesDir;

							if( !SAFBIKComputeBasisLockZ( out headBaseBasis, ref xDir, ref yDir, ref zDir ) ) {
								headBaseBasis = neckBaseBasis;
							}
						}

						Quaternion worldRotation;
						SAFBIKMatMultGetRot( out worldRotation, ref headBaseBasis, ref _headBone._baseToWorldBasis );
						if( _eyesEffector.positionWeight < 1.0f - IKEpsilon ) {
							Quaternion neckBoneWorldRotation = _neckBone.worldRotation;
							Quaternion headFromWorldRotation;
							SAFBIKQuatMultNorm3Inv1( out headFromWorldRotation, ref neckBoneWorldRotation, ref neckBonePrevRotation, ref headBonePrevRotation );
							Quaternion headWorldRotation = Quaternion.Lerp( headFromWorldRotation, worldRotation, _eyesEffector.positionWeight );
							_headBone.worldRotation = headWorldRotation;
							SAFBIKMatSetRotMult( out headBaseBasis, ref headWorldRotation, ref _headBone._worldToBaseRotation );
						} else {
							_headBone.worldRotation = worldRotation;
						}
					}

					Matrix3x3 headBasis;
					SAFBIKMatMult( out headBasis, ref headBaseBasis, ref _internalValues.defaultRootBasisInv );

					if( _isEnabledCustomEyes ) {
						fullBodyIK._SolveCustomEyes( ref neckBasis, ref headBasis, ref headBaseBasis );
                    } else {
						_SolveEyes( ref neckBasis, ref headBasis, ref headBaseBasis, ref headBonePrevRotation, ref leftEyeBonePrevRotation, ref rightEyeBonePrevRotation );
					}
				}
			}