/// <summary> /// For UI we must calculate it differently /// </summary> protected override Quaternion CalculateTargetRotation(FTail_Point tailPoint) { if (Lock2D) { return(CalculateFor2D(tailPoint)); } else { return(base.CalculateTargetRotation(tailPoint)); } }
/// <summary> /// 모든 꼬리 변환을 자유롭게 이동할 수 있도록 연결 해제 /// </summary> protected virtual void PrepareTailPoints() { proceduralPoints = new List <FTail_Point>(); for (int i = 0; i < TailTransforms.Count; i++) { FTail_Point p = new FTail_Point(); p.index = i; p.Position = TailTransforms[i].position; p.Rotation = TailTransforms[i].rotation; p.InitialPosition = TailTransforms[i].localPosition; p.InitialRotation = TailTransforms[i].localRotation; proceduralPoints.Add(p); } }
// V1.1 and V1.1.1/2 /// <summary> /// 꼬리 변환 위치 및 회전 설정 한 꼬리 세그먼트의 목표 회전을 계산합니다. /// 2D 회전과 같은 일부 예외 계산을 위해 재정의합니다. /// </summary> protected virtual Quaternion CalculateTargetRotation(Vector3 startLookPos, Vector3 currentPos, FTail_Point previousTailPoint = null, FTail_Point currentTailPoint = null, int lookDirectionFixIndex = 0) { Quaternion targetRotation; //V1.2.5 int fixDirForw = lookDirectionFixIndex + 1; if (lookDirectionFixIndex == -1) { fixDirForw = 0; lookDirectionFixIndex = 0; } if (FullCorrection) { targetRotation = Quaternion.identity; bool rotationCollision = false; if (UseCollision) { if (collisionFlags[fixDirForw] > 0f) { if (collisionOffsets[fixDirForw] != Vector3.zero) { rotationCollision = true; } } } if (!rotationCollision) { if (RolledBones) { targetRotation = Quaternion.LookRotation(startLookPos - currentPos, previousTailPoint.TransformDirection(-lookBackDirections[fixDirForw] * 0.99f)); } else { targetRotation = Quaternion.LookRotation(startLookPos - currentPos, previousTailPoint.TransformDirection(AxisLookBack)); } } else { //Quaternion target = Quaternion.LookRotation(collisionOffsets[fixDirForw], previousTailPoint.TransformDirection(AxisLookBack)); //// Quaternion target = Quaternion.LookRotation(collisionOffsets[fixDirForw], previousTailPoint.TransformDirection(AxisLookBack)) * Quaternion.FromToRotation(tailLookDirections[lookDirectionFixIndex], ExtraToDirection); //targetRotation *= Quaternion.Slerp(Quaternion.identity, target, collisionFlags[fixDirForw]); Vector3 tailDirection = (startLookPos - currentPos).normalized; Vector3 upwards; if (RolledBones) { upwards = previousTailPoint.TransformDirection(-lookBackDirections[fixDirForw] * 0.99f); } else { upwards = previousTailPoint.TransformDirection(AxisLookBack); } Vector3 smoothedDirection = Vector3.Slerp(tailDirection, (tailDirection + collisionOffsets[currentTailPoint.index]).normalized, collisionFlags[fixDirForw]); targetRotation = Quaternion.LookRotation(smoothedDirection, upwards); } if (GravityPower != Vector2.zero) { float mul = 10 / (fixDirForw * 2.5f + 1); targetRotation *= Quaternion.Euler(GravityPower.y * mul, GravityPower.x * mul, 0f); } targetRotation *= Quaternion.FromToRotation(tailLookDirections[lookDirectionFixIndex], ExtraToDirection); if (AnimateCorrections) { targetRotation *= animatedCorrections[fixDirForw]; } else { targetRotation *= lookBackOffsets[fixDirForw]; } } else { targetRotation = Quaternion.identity; bool rotationCollision = false; if (UseCollision) { if (collisionFlags[fixDirForw] > 0f) { if (collisionOffsets[fixDirForw] != Vector3.zero) { #region Experiments //Quaternion target = Quaternion.LookRotation(collisionOffsets[fixDirForw], previousTailPoint.TransformDirection(AxisLookBack)); ////Quaternion target = Quaternion.LookRotation(collisionOffsets[fixDirForw], previousTailPoint.TransformDirection(AxisLookBack)) * Quaternion.FromToRotation(tailLookDirections[lookDirectionFixIndex], ExtraToDirection); //targetRotation *= Quaternion.Slerp(Quaternion.identity, target, collisionFlags[fixDirForw]); //Quaternion target = Quaternion.LookRotation(collisionOffsets[fixDirForw], previousTailPoint.TransformDirection(AxisLookBack)); //targetRotation *= Quaternion.Slerp(Quaternion.identity, target, collisionFlags[fixDirForw]); //Vector3 tailDirection = (startLookPos - currentPos).normalized; //Vector3 smoothedDirection = Vector3.Slerp(tailDirection, (tailDirection + collisionOffsets[fixDirForw]).normalized, collisionFlags[fixDirForw]); //targetRotation = Quaternion.LookRotation(smoothedDirection, previousTailPoint.TransformDirection(AxisLookBack * Mathf.Sign(FVectorMethods.VectorSum(AxisCorrection)))); //Vector3 smoothedDirection = Vector3.Slerp(tailDirection, (tailDirection + collisionOffsets[fixDirForw]).normalized, collisionFlags[fixDirForw]); //Vector3 upwards = previousTailPoint.TransformDirection(AxisLookBack * Mathf.Sign(FVectorMethods.VectorSum(AxisCorrection))); //Vector3 tailDirection = (startLookPos - currentPos).normalized; //targetRotation = Quaternion.LookRotation(tailDirection, upwards); //targetRotation *= Quaternion.Slerp( Quaternion.identity, Quaternion.LookRotation(collisionOffsets[currentTailPoint.index], upwards), collisionFlags[fixDirForw]); #endregion Experiments Vector3 tailDirection = (startLookPos - currentPos).normalized; Vector3 smoothedDirection = Vector3.Slerp(tailDirection, (tailDirection + collisionOffsets[currentTailPoint.index]).normalized, collisionFlags[fixDirForw]); targetRotation = Quaternion.LookRotation(smoothedDirection, previousTailPoint.TransformDirection(AxisLookBack)); rotationCollision = true; } } } if (!rotationCollision) { targetRotation = Quaternion.LookRotation(startLookPos - currentPos, previousTailPoint.TransformDirection(AxisLookBack * Mathf.Sign(FVectorMethods.VectorSum(AxisCorrection)))); } if (GravityPower != Vector2.zero) { float mul = 10 / (fixDirForw * 2.5f + 1); targetRotation *= Quaternion.Euler(GravityPower.y * mul, GravityPower.x * mul, 0f); } if (ExtraCorrectionOptions) { targetRotation *= Quaternion.FromToRotation(ExtraFromDirection, ExtraToDirection); } } return(targetRotation); }
/// <summary> /// 주어진 변형 목록에 대한 꼬리 모양의 움직임 애니메이션 논리 계산하기 /// </summary> protected virtual void MotionCalculations() { if (UseCollision) { if (collisionOffsets == null) { AddColliders(); } } if (preAutoCorrect != UseAutoCorrectLookAxis) { ApplyAutoCorrection(); preAutoCorrect = UseAutoCorrectLookAxis; } if (AnimateCorrections) { for (int i = 0; i < TailTransforms.Count; i++) { animatedCorrections[i] = TailTransforms[i].localRotation; } } // 애니메이션 변수 계산하기 float posDelta; float rotDelta; if (UpdateClock == EFUpdateClock.FixedUpdate) { posDelta = Time.fixedDeltaTime * PositionSpeed; rotDelta = Time.fixedDeltaTime * RotationSpeed; } else { if (SmoothDeltaTime) { posDelta = Time.smoothDeltaTime * PositionSpeed; rotDelta = Time.smoothDeltaTime * RotationSpeed; } else { posDelta = Time.deltaTime * PositionSpeed; rotDelta = Time.deltaTime * RotationSpeed; } } if (!RootToParent) { proceduralPoints[0].Position = TailTransforms[0].position; } else { // Supporting root parent motion FTail_Point currentTailPoint = proceduralPoints[0]; Vector3 startLookPosition = TailTransforms[0].parent.position; Vector3 translationVector; translationVector = TailTransforms[0].parent.TransformDirection(tailLookDirections[0]); Vector3 targetPosition = TailTransforms[0].parent.transform.position + (translationVector * -1f * (distances[0] * StretchMultiplier)); FTail_Point temporaryPoint = new FTail_Point { index = 0, Position = TailTransforms[0].parent.position, Rotation = TailTransforms[0].parent.rotation }; Quaternion targetLookRotation = CalculateTargetRotation(startLookPosition, currentTailPoint.Position, temporaryPoint, currentTailPoint, -1); proceduralPoints[0].Position = Vector3.Lerp(currentTailPoint.Position, targetPosition, posDelta); proceduralPoints[0].Rotation = Quaternion.Lerp(currentTailPoint.Rotation, targetLookRotation, rotDelta); } for (int i = 1; i < proceduralPoints.Count; i++) { FTail_Point previousTailPoint = proceduralPoints[i - 1]; FTail_Point currentTailPoint = proceduralPoints[i]; Vector3 startLookPosition = previousTailPoint.Position; Vector3 translationVector; if (FullCorrection) { translationVector = previousTailPoint.TransformDirection(tailLookDirections[i - 1]); } else { translationVector = previousTailPoint.TransformDirection(AxisCorrection); } Vector3 targetPosition = previousTailPoint.Position + (translationVector * -1f * (distances[i] * StretchMultiplier)); Quaternion targetLookRotation = CalculateTargetRotation(startLookPosition, currentTailPoint.Position, previousTailPoint, currentTailPoint, i - 1); proceduralPoints[i].Position = Vector3.Lerp(currentTailPoint.Position, targetPosition, posDelta); proceduralPoints[i].Rotation = Quaternion.Lerp(currentTailPoint.Rotation, targetLookRotation, rotDelta); if (UseCollision) { if (collisionFlags[i] > 0f) { collisionFlags[i] -= Time.deltaTime * 4f; } else { collisionOffsets[i] = Vector3.zero; } } } if (UseCollision) { for (int i = 1; i < collisionContacts.Count; i++) { UseCollisionContact(i); } } //if (UseCollision) for (int i = collisionContacts.Count-1; i >= 1; i--) UseCollisionContact(i); }
/// <summary> /// Adding sinus wave rotation with limiting option for first bone before other calculations /// </summary> public override void CalculateOffsets() { // Just calculating animation variables float delta; if (UpdateClock == EFUpdateClock.FixedUpdate) { delta = Time.fixedDeltaTime; } else { delta = Time.deltaTime; } if (UseWaving) { waveTime += delta * (2 * WavingSpeed); // It turned out to be problematic // When using clamp setting rotation was flipping other axes // So we push rotation in x axis (most common to this problem) if (UseXLimitation) { Vector3 worldRotation = TailTransforms[0].rotation.eulerAngles; float wrappedWorldAngle = LimitAngle360(worldRotation.x); if (wrappedWorldAngle < WorldXDontGoUnder) { pushTimer = PushTime; } if (pushTimer > 0f) { TrueTailRotationOffset = Vector3.Lerp(TrueTailRotationOffset, Vector3.zero, delta * PushPower); pushTimer -= delta; } else { TrueTailRotationOffset = Vector3.Lerp(TrueTailRotationOffset, TailRotationOffset, delta * PushPower * 0.7f); } } Vector3 rot = firstBoneInitialRotation + TrueTailRotationOffset; float sinVal = Mathf.Sin(waveTime) * (30f * WavingRange); rot += sinVal * WavingAxis; if (rootTransform) { proceduralPoints[0].Rotation = rootTransform.rotation * Quaternion.Euler(rot); } else { proceduralPoints[0].Rotation = TailTransforms[0].transform.rotation * Quaternion.Euler(rot); } } else { if (rootTransform) { proceduralPoints[0].Rotation = rootTransform.rotation * Quaternion.Euler(firstBoneInitialRotation); } else { proceduralPoints[0].Rotation = TailTransforms[0].transform.rotation * Quaternion.Euler(firstBoneInitialRotation); } } if (preAutoCorrect != UseAutoCorrectLookAxis) { ApplyAutoCorrection(); preAutoCorrect = UseAutoCorrectLookAxis; } proceduralPoints[0].Position = TailTransforms[0].position; // Just calculating animation variables float posDelta; float rotDelta; if (UpdateClock == EFUpdateClock.FixedUpdate) { posDelta = Time.fixedDeltaTime * PositionSpeed; rotDelta = Time.fixedDeltaTime * RotationSpeed; } else { posDelta = Time.deltaTime * PositionSpeed; rotDelta = Time.deltaTime * RotationSpeed; } for (int i = 1; i < proceduralPoints.Count; i++) { FTail_Point previousTailPoint = proceduralPoints[i - 1]; FTail_Point currentTailPoint = proceduralPoints[i]; Vector3 startLookPosition = previousTailPoint.Position; Vector3 translationVector; if (FullCorrection) { translationVector = previousTailPoint.TransformDirection(tailLookDirections[i - 1]); } else { translationVector = previousTailPoint.TransformDirection(AxisCorrection); } Vector3 targetPosition = previousTailPoint.Position + (translationVector * -1f * (distances[i] * StretchMultiplier)); proceduralPoints[i].Position = Vector3.Lerp(currentTailPoint.Position, targetPosition, posDelta); Quaternion targetLookRotation = CalculateTargetRotation(startLookPosition, currentTailPoint.Position, previousTailPoint, currentTailPoint, i - 1); proceduralPoints[i].Rotation = Quaternion.Lerp(currentTailPoint.Rotation, targetLookRotation, rotDelta); } SetTailTransformsFromPoints(); }
protected override Quaternion CalculateTargetRotation(Vector3 startLookPos, Vector3 currentPos, FTail_Point previousTailPoint = null, FTail_Point currentTailPoint = null, int lookDirectionFixIndex = 0) { if (Lock2D) { return(FLogicMethods.TopDownAnglePosition2D(startLookPos, currentPos)); } else { return(base.CalculateTargetRotation(startLookPos, currentPos, previousTailPoint, currentTailPoint, lookDirectionFixIndex)); } }
protected Quaternion CalculateFor2D(FTail_Point tailPoint) { Quaternion targetRotation; if (FullCorrection) { Vector3 startLookPos = tailPoint.BackPoint.Position; Vector3 lookingAt = tailPoint.RotationTargetPos; targetRotation = Quaternion.identity; if (LookUpMethod != FELookUpMethod.Parental) { startLookPos += tailPoint.BackPoint.TransformDirection(tailPoint.BackPoint.LookDirection) * tailPoint.InitBoneLength * tailPoint.ScaleFactor * sensitivityPower; startLookPos -= (tailPoint.BackPoint.PreCollisionPosition - tailPoint.BackPoint.Position) * CollisionSwapping; if (startLookPos - lookingAt != Vector3.zero) { targetRotation = FLogicMethods.TopDownAnglePosition2D(lookingAt, startLookPos); } targetRotation *= Quaternion.FromToRotation(tailPoint.BackPoint.LookDirection, ExtraToDirection); } else // Parental method { startLookPos += tailPoint.BackPoint.TransformDirection(tailPoint.BackPoint.LookDirection) * tailPoint.InitBoneLength * tailPoint.ScaleFactor * sensitivityPower; Vector3 targetPos = lookingAt - startLookPos; Quaternion targetingRot = Quaternion.FromToRotation(tailPoint.BackPoint.TransformDirection(tailPoint.Transform.localPosition), targetPos); targetRotation = targetingRot * tailPoint.BackPoint.Rotation; } if (Curving != Vector3.zero) { float mul = 10 / ((float)tailPoint.index * 4.5f + 1f); targetRotation *= Quaternion.Euler(Curving.y * mul, Curving.x * mul, 0f); } targetRotation *= tailPoint.Correction; } else { targetRotation = Quaternion.identity; Vector3 startLookPos = tailPoint.BackPoint.Position; Vector3 lookingAt = tailPoint.RotationTargetPos; startLookPos += tailPoint.BackPoint.TransformDirection(tailPoint.BackPoint.LookDirection) * tailPoint.InitBoneLength * sensitivityPower; startLookPos -= (tailPoint.BackPoint.PreCollisionPosition - tailPoint.BackPoint.Position) * CollisionSwapping; if (startLookPos - lookingAt != Vector3.zero) { targetRotation = FLogicMethods.TopDownAnglePosition2D(startLookPos, lookingAt); } //targetRotation = Quaternion.LookRotation(startLookPos - lookingAt, tailPoint.BackPoint.TransformDirection(AxisLookBack * Mathf.Sign(FVectorMethods.VectorSum(AxisCorrection)))); if (Curving != Vector3.zero) { float mul = 10f / ((float)tailPoint.index * 4.5f + 1f); targetRotation *= Quaternion.Euler(Curving.y * mul, Curving.x * mul, 0f); } if (ExtraCorrectionOptions) { targetRotation *= Quaternion.FromToRotation(ExtraFromDirection, ExtraToDirection); } } return(targetRotation); }