/// <summary> /// Adjust the rigOrientation to put the camera within the screen bounds. /// If deltaTime >= 0 then damping will be applied. /// Assumes that currentOrientation fwd is such that input rigOrientation's /// local up is NEVER NEVER NEVER pointing downwards, relative to /// state.ReferenceUp. If this condition is violated /// then you will see crazy spinning. That's the symptom. /// </summary> private bool RotateToScreenBounds( ref CameraState state, Rect screenRect, ref Quaternion rigOrientation, float fov, float fovH, float deltaTime) { Vector3 targetDir = TrackedPoint - state.CorrectedPosition; Vector2 rotToRect = rigOrientation.GetCameraRotationToTarget(targetDir, state.ReferenceUp); // Bring it to the edge of screenRect, if outside. Leave it alone if inside. ClampVerticalBounds(ref screenRect, targetDir, state.ReferenceUp, fov); float min = (screenRect.yMin - 0.5f) * fov; float max = (screenRect.yMax - 0.5f) * fov; if (rotToRect.x < min) { rotToRect.x -= min; } else if (rotToRect.x > max) { rotToRect.x -= max; } else { rotToRect.x = 0; } min = (screenRect.xMin - 0.5f) * fovH; max = (screenRect.xMax - 0.5f) * fovH; if (rotToRect.y < min) { rotToRect.y -= min; } else if (rotToRect.y > max) { rotToRect.y -= max; } else { rotToRect.y = 0; } // Apply damping if (deltaTime >= 0) { rotToRect.x = Damper.Damp(rotToRect.x, m_VerticalDamping, deltaTime); rotToRect.y = Damper.Damp(rotToRect.y, m_HorizontalDamping, deltaTime); } // Rotate rigOrientation = rigOrientation.ApplyCameraRotation(rotToRect, state.ReferenceUp); #if false // GML this gives false positives when the camera is moving. // The way to address this would be to grow the hard rect by the amount // that it would be damped return(Mathf.Abs(rotToRect.x) > Epsilon || Mathf.Abs(rotToRect.y) > Epsilon); #else return(false); #endif }
/// <summary> /// Adjust the rigOrientation to put the camera within the screen bounds. /// If deltaTime >= 0 then damping will be applied. /// Assumes that currentOrientation fwd is such that input rigOrientation's /// local up is NEVER NEVER NEVER pointing downwards, relative to /// state.ReferenceUp. If this condition is violated /// then you will see crazy spinning. That's the symptom. /// </summary> private Quaternion RotateToScreenBounds( ref CameraState state, Rect screenRect, Quaternion rigOrientation, float fov, float fovH, float deltaTime) { Vector3 targetDir = state.ReferenceLookAt - state.CorrectedPosition; Vector2 rotToRect = rigOrientation.GetCameraRotationToTarget(targetDir, state.ReferenceUp); // Bring it to the edge of screenRect, if outside. Leave it alone if inside. ClampVerticalBounds(ref screenRect, targetDir, state.ReferenceUp, fov); float min = (screenRect.yMin - 0.5f) * fov; float max = (screenRect.yMax - 0.5f) * fov; if (rotToRect.x < min) { rotToRect.x -= min; } else if (rotToRect.x > max) { rotToRect.x -= max; } else { rotToRect.x = 0; } min = (screenRect.xMin - 0.5f) * fovH; max = (screenRect.xMax - 0.5f) * fovH; if (rotToRect.y < min) { rotToRect.y -= min; } else if (rotToRect.y > max) { rotToRect.y -= max; } else { rotToRect.y = 0; } // Apply damping if (deltaTime > 0) { if (Mathf.Abs(rotToRect.x) > UnityVectorExtensions.Epsilon) { rotToRect.x *= deltaTime / Mathf.Max(m_VerticalDamping * kDampingScale, deltaTime); } if (Mathf.Abs(rotToRect.y) > UnityVectorExtensions.Epsilon) { rotToRect.y *= deltaTime / Mathf.Max(m_HorizontalDamping * kDampingScale, deltaTime); } } // Rotate return(rigOrientation.ApplyCameraRotation(rotToRect, state.ReferenceUp)); }
/// <summary> /// Adjust the rigOrientation to put the camera within the screen bounds. /// If deltaTime >= 0 then damping will be applied. /// Assumes that currentOrientation fwd is such that input rigOrientation's /// local up is NEVER NEVER NEVER pointing downwards, relative to /// state.ReferenceUp. If this condition is violated /// then you will see crazy spinning. That's the symptom. /// </summary> private void RotateToScreenBounds( ref CameraState state, Rect screenRect, Vector3 trackedPoint, ref Quaternion rigOrientation, float fov, float fovH, float deltaTime) { Vector3 targetDir = trackedPoint - state.CorrectedPosition; Vector2 rotToRect = rigOrientation.GetCameraRotationToTarget(targetDir, state.ReferenceUp); // Bring it to the edge of screenRect, if outside. Leave it alone if inside. ClampVerticalBounds(ref screenRect, targetDir, state.ReferenceUp, fov); float min = (screenRect.yMin - 0.5f) * fov; float max = (screenRect.yMax - 0.5f) * fov; if (rotToRect.x < min) { rotToRect.x -= min; } else if (rotToRect.x > max) { rotToRect.x -= max; } else { rotToRect.x = 0; } min = (screenRect.xMin - 0.5f) * fovH; max = (screenRect.xMax - 0.5f) * fovH; if (rotToRect.y < min) { rotToRect.y -= min; } else if (rotToRect.y > max) { rotToRect.y -= max; } else { rotToRect.y = 0; } // Apply damping if (deltaTime >= 0 && VirtualCamera.PreviousStateIsValid) { rotToRect.x = VirtualCamera.DetachedLookAtTargetDamp( rotToRect.x, m_VerticalDamping, deltaTime); rotToRect.y = VirtualCamera.DetachedLookAtTargetDamp( rotToRect.y, m_HorizontalDamping, deltaTime); } // Rotate rigOrientation = rigOrientation.ApplyCameraRotation(rotToRect, state.ReferenceUp); }
/// <summary> /// Adjust the rigOrientation to put the camera within the screen bounds. /// If deltaTime >= 0 then damping will be applied. /// Assumes that currentOrientation fwd is such that input rigOrientation's /// local up is NEVER NEVER NEVER pointing downwards, relative to /// state.ReferenceUp. If this condition is violated /// then you will see crazy spinning. That's the symptom. /// </summary> private Quaternion PlaceWithinScreenBounds( ref CameraState state, Rect screenRect, Quaternion rigOrientation, float fovH, float deltaTime) { Vector3 targetDir = state.ReferenceLookAt - state.CorrectedPosition; Vector2 rotToRect = rigOrientation.GetCameraRotationToTarget(targetDir, state.ReferenceUp); // Bring it to the edge of screenRect, if outside. Leave it alone if inside. ClampVerticalBounds(ref screenRect, targetDir, state.ReferenceUp, state.Lens.FieldOfView); float min = (screenRect.yMin - 0.5f) * state.Lens.FieldOfView; float max = (screenRect.yMax - 0.5f) * state.Lens.FieldOfView; if (rotToRect.x < min) { rotToRect.x -= min; } else if (rotToRect.x > max) { rotToRect.x -= max; } else { rotToRect.x = 0; } min = (screenRect.xMin - 0.5f) * fovH; max = (screenRect.xMax - 0.5f) * fovH; if (rotToRect.y < min) { rotToRect.y -= min; } else if (rotToRect.y > max) { rotToRect.y -= max; } else { rotToRect.y = 0; } // Apply damping if (deltaTime > 0) { rotToRect.x *= deltaTime / Mathf.Max(VerticalSoftTrackingSpeed, deltaTime); rotToRect.y *= deltaTime / Mathf.Max(HorizontalSoftTrackingSpeed, deltaTime); } // Rotate return(rigOrientation.ApplyCameraRotation(rotToRect, state.ReferenceUp)); }
private bool RotateToScreenBounds(ref CameraState state, Rect screenRect, ref Quaternion rigOrientation, float fov, float fovH, float deltaTime) { Vector3 vector = this.TrackedPoint - state.CorrectedPosition; Vector2 cameraRotationToTarget = rigOrientation.GetCameraRotationToTarget(vector, state.ReferenceUp); this.ClampVerticalBounds(ref screenRect, vector, state.ReferenceUp, fov); float num = (screenRect.yMin - 0.5f) * fov; float num2 = (screenRect.yMax - 0.5f) * fov; if (cameraRotationToTarget.x < num) { cameraRotationToTarget.x -= num; } else if (cameraRotationToTarget.x > num2) { cameraRotationToTarget.x -= num2; } else { cameraRotationToTarget.x = 0f; } num = (screenRect.xMin - 0.5f) * fovH; num2 = (screenRect.xMax - 0.5f) * fovH; if (cameraRotationToTarget.y < num) { cameraRotationToTarget.y -= num; } else if (cameraRotationToTarget.y > num2) { cameraRotationToTarget.y -= num2; } else { cameraRotationToTarget.y = 0f; } if (deltaTime >= 0f) { cameraRotationToTarget.x = Damper.Damp(cameraRotationToTarget.x, this.m_VerticalDamping, deltaTime); cameraRotationToTarget.y = Damper.Damp(cameraRotationToTarget.y, this.m_HorizontalDamping, deltaTime); } rigOrientation = rigOrientation.ApplyCameraRotation(cameraRotationToTarget, state.ReferenceUp); return(false); }
/// <summary>Intelligently blend the contents of two states.</summary> /// <param name="stateA">The first state, corresponding to t=0</param> /// <param name="stateB">The second state, corresponding to t=1</param> /// <param name="t">How much to interpolate. Internally clamped to 0..1</param> /// <returns>Linearly interpolated CameraState</returns> public static CameraState Lerp(CameraState stateA, CameraState stateB, float t) { t = Mathf.Clamp01(t); float adjustedT = t; CameraState state = new CameraState(); // Combine the blend hints intelligently if (((stateA.BlendHint & stateB.BlendHint) & BlendHintValue.NoPosition) != 0) { state.BlendHint |= BlendHintValue.NoPosition; } if (((stateA.BlendHint & stateB.BlendHint) & BlendHintValue.NoOrientation) != 0) { state.BlendHint |= BlendHintValue.NoOrientation; } if (((stateA.BlendHint & stateB.BlendHint) & BlendHintValue.NoLens) != 0) { state.BlendHint |= BlendHintValue.NoLens; } if (((stateA.BlendHint | stateB.BlendHint) & BlendHintValue.SphericalPositionBlend) != 0) { state.BlendHint |= BlendHintValue.SphericalPositionBlend; } if (((stateA.BlendHint | stateB.BlendHint) & BlendHintValue.CylindricalPositionBlend) != 0) { state.BlendHint |= BlendHintValue.CylindricalPositionBlend; } if (((stateA.BlendHint | stateB.BlendHint) & BlendHintValue.NoLens) == 0) { state.Lens = LensSettings.Lerp(stateA.Lens, stateB.Lens, t); } else if (((stateA.BlendHint & stateB.BlendHint) & BlendHintValue.NoLens) == 0) { if ((stateA.BlendHint & BlendHintValue.NoLens) != 0) { state.Lens = stateB.Lens; } else { state.Lens = stateA.Lens; } } state.ReferenceUp = Vector3.Slerp(stateA.ReferenceUp, stateB.ReferenceUp, t); state.ShotQuality = Mathf.Lerp(stateA.ShotQuality, stateB.ShotQuality, t); state.PositionCorrection = ApplyPosBlendHint( stateA.PositionCorrection, stateA.BlendHint, stateB.PositionCorrection, stateB.BlendHint, state.PositionCorrection, Vector3.Lerp(stateA.PositionCorrection, stateB.PositionCorrection, t)); state.OrientationCorrection = ApplyRotBlendHint( stateA.OrientationCorrection, stateA.BlendHint, stateB.OrientationCorrection, stateB.BlendHint, state.OrientationCorrection, Quaternion.Slerp(stateA.OrientationCorrection, stateB.OrientationCorrection, t)); // LookAt target if (!stateA.HasLookAt || !stateB.HasLookAt) { state.ReferenceLookAt = kNoPoint; } else { // Re-interpolate FOV to preserve target composition, if possible float fovA = stateA.Lens.FieldOfView; float fovB = stateB.Lens.FieldOfView; if (((stateA.BlendHint | stateB.BlendHint) & BlendHintValue.NoLens) == 0 && !state.Lens.Orthographic && !Mathf.Approximately(fovA, fovB)) { LensSettings lens = state.Lens; lens.FieldOfView = InterpolateFOV( fovA, fovB, Mathf.Max((stateA.ReferenceLookAt - stateA.CorrectedPosition).magnitude, stateA.Lens.NearClipPlane), Mathf.Max((stateB.ReferenceLookAt - stateB.CorrectedPosition).magnitude, stateB.Lens.NearClipPlane), t); state.Lens = lens; // Make sure we preserve the screen composition through FOV changes adjustedT = Mathf.Abs((lens.FieldOfView - fovA) / (fovB - fovA)); } // Linear interpolation of lookAt target point state.ReferenceLookAt = Vector3.Lerp( stateA.ReferenceLookAt, stateB.ReferenceLookAt, adjustedT); } // Raw position state.RawPosition = ApplyPosBlendHint( stateA.RawPosition, stateA.BlendHint, stateB.RawPosition, stateB.BlendHint, state.RawPosition, state.InterpolatePosition( stateA.RawPosition, stateA.ReferenceLookAt, stateB.RawPosition, stateB.ReferenceLookAt, t)); // Interpolate the LookAt in Screen Space if requested if (state.HasLookAt && ((stateA.BlendHint | stateB.BlendHint) & BlendHintValue.RadialAimBlend) != 0) { state.ReferenceLookAt = state.RawPosition + Vector3.Slerp( stateA.ReferenceLookAt - state.RawPosition, stateB.ReferenceLookAt - state.RawPosition, adjustedT); } // Clever orientation interpolation Quaternion newOrient = state.RawOrientation; if (((stateA.BlendHint | stateB.BlendHint) & BlendHintValue.NoOrientation) == 0) { Vector3 dirTarget = Vector3.zero; if (state.HasLookAt)//&& ((stateA.BlendHint | stateB.BlendHint) & BlendHintValue.RadialAimBlend) == 0) { // If orientations are different, use LookAt to blend them float angle = Quaternion.Angle(stateA.RawOrientation, stateB.RawOrientation); if (angle > UnityVectorExtensions.Epsilon) { dirTarget = state.ReferenceLookAt - state.CorrectedPosition; } } if (dirTarget.AlmostZero() || ((stateA.BlendHint | stateB.BlendHint) & BlendHintValue.IgnoreLookAtTarget) != 0) { // Don't know what we're looking at - can only slerp newOrient = UnityQuaternionExtensions.SlerpWithReferenceUp( stateA.RawOrientation, stateB.RawOrientation, t, state.ReferenceUp); } else { // Rotate while preserving our lookAt target dirTarget = dirTarget.normalized; if ((dirTarget - state.ReferenceUp).AlmostZero() || (dirTarget + state.ReferenceUp).AlmostZero()) { // Looking up or down at the pole newOrient = UnityQuaternionExtensions.SlerpWithReferenceUp( stateA.RawOrientation, stateB.RawOrientation, t, state.ReferenceUp); } else { // Put the target in the center newOrient = Quaternion.LookRotation(dirTarget, state.ReferenceUp); // Blend the desired offsets from center Vector2 deltaA = -stateA.RawOrientation.GetCameraRotationToTarget( stateA.ReferenceLookAt - stateA.CorrectedPosition, stateA.ReferenceUp); Vector2 deltaB = -stateB.RawOrientation.GetCameraRotationToTarget( stateB.ReferenceLookAt - stateB.CorrectedPosition, stateB.ReferenceUp); newOrient = newOrient.ApplyCameraRotation( Vector2.Lerp(deltaA, deltaB, adjustedT), state.ReferenceUp); } } } state.RawOrientation = ApplyRotBlendHint( stateA.RawOrientation, stateA.BlendHint, stateB.RawOrientation, stateB.BlendHint, state.RawOrientation, newOrient); // Accumulate the custom blendables and apply the weights for (int i = 0; i < stateA.NumCustomBlendables; ++i) { CustomBlendable b = stateA.GetCustomBlendable(i); b.m_Weight *= (1 - t); if (b.m_Weight > UnityVectorExtensions.Epsilon) { state.AddCustomBlendable(b); } } for (int i = 0; i < stateB.NumCustomBlendables; ++i) { CustomBlendable b = stateB.GetCustomBlendable(i); b.m_Weight *= t; if (b.m_Weight > UnityVectorExtensions.Epsilon) { state.AddCustomBlendable(b); } } return(state); }
/// <summary>Applies the composer rules and orients the camera accordingly</summary> /// <param name="curState">The current camera state</param> /// <param name="deltaTime">Used for calculating damping. If less than /// zero, then target will snap to the center of the dead zone.</param> public override void MutateCameraState(ref CameraState curState, float deltaTime) { if (!IsValid || !curState.HasLookAt) { return; } // Correct the tracked point in the event that it's behind the camera // while the real target is in front if (!(TrackedPoint - curState.ReferenceLookAt).AlmostZero()) { Vector3 mid = Vector3.Lerp(curState.CorrectedPosition, curState.ReferenceLookAt, 0.5f); Vector3 toLookAt = curState.ReferenceLookAt - mid; Vector3 toTracked = TrackedPoint - mid; if (Vector3.Dot(toLookAt, toTracked) < 0) { float t = Vector3.Distance(curState.ReferenceLookAt, mid) / Vector3.Distance(curState.ReferenceLookAt, TrackedPoint); TrackedPoint = Vector3.Lerp(curState.ReferenceLookAt, TrackedPoint, t); } } float targetDistance = (TrackedPoint - curState.CorrectedPosition).magnitude; if (targetDistance < Epsilon) { if (deltaTime >= 0 && VirtualCamera.PreviousStateIsValid) { curState.RawOrientation = m_CameraOrientationPrevFrame; } return; // navel-gazing, get outa here } // Expensive FOV calculations mCache.UpdateCache(curState.Lens, SoftGuideRect, HardGuideRect, targetDistance); Quaternion rigOrientation = curState.RawOrientation; if (deltaTime < 0 || !VirtualCamera.PreviousStateIsValid) { // No damping, just snap to central bounds, skipping the soft zone rigOrientation = Quaternion.LookRotation( rigOrientation * Vector3.forward, curState.ReferenceUp); Rect rect = mCache.mFovSoftGuideRect; if (m_CenterOnActivate) { rect = new Rect(rect.center, Vector2.zero); // Force to center } RotateToScreenBounds( ref curState, rect, curState.ReferenceLookAt, ref rigOrientation, mCache.mFov, mCache.mFovH, -1); } else { // Start with previous frame's orientation (but with current up) Vector3 dir = m_LookAtPrevFrame - m_CameraPosPrevFrame; if (dir.AlmostZero()) { rigOrientation = Quaternion.LookRotation( m_CameraOrientationPrevFrame * Vector3.forward, curState.ReferenceUp); } else { dir = Quaternion.Euler(curState.PositionDampingBypass) * dir; rigOrientation = Quaternion.LookRotation(dir, curState.ReferenceUp); rigOrientation = rigOrientation.ApplyCameraRotation( -m_ScreenOffsetPrevFrame, curState.ReferenceUp); } // Move target through the soft zone, with damping RotateToScreenBounds( ref curState, mCache.mFovSoftGuideRect, TrackedPoint, ref rigOrientation, mCache.mFov, mCache.mFovH, deltaTime); // Force the actual target (not the lookahead one) into the hard bounds, no damping if (deltaTime < 0 || VirtualCamera.LookAtTargetAttachment > 1 - Epsilon) { RotateToScreenBounds( ref curState, mCache.mFovHardGuideRect, curState.ReferenceLookAt, ref rigOrientation, mCache.mFov, mCache.mFovH, -1); } } m_CameraPosPrevFrame = curState.CorrectedPosition; m_LookAtPrevFrame = TrackedPoint; m_CameraOrientationPrevFrame = UnityQuaternionExtensions.Normalized(rigOrientation); m_ScreenOffsetPrevFrame = m_CameraOrientationPrevFrame.GetCameraRotationToTarget( m_LookAtPrevFrame - curState.CorrectedPosition, curState.ReferenceUp); curState.RawOrientation = m_CameraOrientationPrevFrame; }
/// <summary>Applies the composer rules and orients the camera accordingly</summary> /// <param name="curState">The current camera state</param> /// <param name="deltaTime">Used for calculating damping. If less than /// zero, then target will snap to the center of the dead zone.</param> public override void MutateCameraState(ref CameraState curState, float deltaTime) { // Initialize the state for previous frame if appropriate if (deltaTime < 0) { m_Predictor.Reset(); } if (!IsValid || !curState.HasLookAt) { return; } float targetDistance = (TrackedPoint - curState.CorrectedPosition).magnitude; if (targetDistance < Epsilon) { if (deltaTime >= 0) { curState.RawOrientation = m_CameraOrientationPrevFrame; } return; // navel-gazing, get outa here } float fov, fovH; if (curState.Lens.Orthographic) { // Calculate effective fov - fake it for ortho based on target distance fov = Mathf.Rad2Deg * 2 * Mathf.Atan(curState.Lens.OrthographicSize / targetDistance); fovH = Mathf.Rad2Deg * 2 * Mathf.Atan( curState.Lens.Aspect * curState.Lens.OrthographicSize / targetDistance); } else { fov = curState.Lens.FieldOfView; double radHFOV = 2 * Math.Atan(Math.Tan(fov * Mathf.Deg2Rad / 2) * curState.Lens.Aspect); fovH = (float)(Mathf.Rad2Deg * radHFOV); } Quaternion rigOrientation = curState.RawOrientation; Rect softGuideFOV = ScreenToFOV(SoftGuideRect, fov, fovH, curState.Lens.Aspect); if (deltaTime < 0) { // No damping, just snap to central bounds, skipping the soft zone Rect rect = new Rect(softGuideFOV.center, Vector2.zero); // Force to center RotateToScreenBounds(ref curState, rect, ref rigOrientation, fov, fovH, -1); } else { // Start with previous frame's orientation (but with current up) Vector3 dir = m_LookAtPrevFrame - (m_CameraPosPrevFrame + curState.PositionDampingBypass); if (dir.AlmostZero()) { rigOrientation = Quaternion.LookRotation( m_CameraOrientationPrevFrame * Vector3.forward, curState.ReferenceUp); } else { rigOrientation = Quaternion.LookRotation(dir, curState.ReferenceUp); rigOrientation = rigOrientation.ApplyCameraRotation( -m_ScreenOffsetPrevFrame, curState.ReferenceUp); } // First force the previous rotation into the hard bounds, no damping, // then Now move it through the soft zone, with damping Rect hardGuideFOV = ScreenToFOV(HardGuideRect, fov, fovH, curState.Lens.Aspect); if (!RotateToScreenBounds(ref curState, hardGuideFOV, ref rigOrientation, fov, fovH, -1)) { RotateToScreenBounds(ref curState, softGuideFOV, ref rigOrientation, fov, fovH, deltaTime); } } m_CameraPosPrevFrame = curState.CorrectedPosition; m_LookAtPrevFrame = TrackedPoint; m_CameraOrientationPrevFrame = UnityQuaternionExtensions.Normalized(rigOrientation); m_ScreenOffsetPrevFrame = m_CameraOrientationPrevFrame.GetCameraRotationToTarget( m_LookAtPrevFrame - curState.CorrectedPosition, curState.ReferenceUp); curState.RawOrientation = m_CameraOrientationPrevFrame; }
public override void MutateCameraState(ref CameraState curState, float deltaTime) { if (deltaTime < 0f) { this.m_Predictor.Reset(); } if (!this.IsValid || !curState.HasLookAt) { return; } float magnitude = (this.TrackedPoint - curState.CorrectedPosition).magnitude; if (magnitude < 0.0001f) { if (deltaTime >= 0f) { curState.RawOrientation = this.m_CameraOrientationPrevFrame; } return; } float num; float fovH; if (curState.Lens.Orthographic) { num = 114.59156f * Mathf.Atan(curState.Lens.OrthographicSize / magnitude); fovH = 114.59156f * Mathf.Atan(curState.Lens.Aspect * curState.Lens.OrthographicSize / magnitude); } else { num = curState.Lens.FieldOfView; double num2 = 2.0 * Math.Atan(Math.Tan((double)(num * 0.0174532924f / 2f)) * (double)curState.Lens.Aspect); fovH = (float)(57.295780181884766 * num2); } Quaternion quaternion = curState.RawOrientation; Rect screenRect = this.ScreenToFOV(this.SoftGuideRect, num, fovH, curState.Lens.Aspect); if (deltaTime < 0f) { Rect screenRect2 = new Rect(screenRect.center, Vector2.zero); this.RotateToScreenBounds(ref curState, screenRect2, ref quaternion, num, fovH, -1f); } else { Vector3 vector = this.m_LookAtPrevFrame - (this.m_CameraPosPrevFrame + curState.PositionDampingBypass); if (vector.AlmostZero()) { quaternion = Quaternion.LookRotation(this.m_CameraOrientationPrevFrame * Vector3.forward, curState.ReferenceUp); } else { quaternion = Quaternion.LookRotation(vector, curState.ReferenceUp); quaternion = quaternion.ApplyCameraRotation(-this.m_ScreenOffsetPrevFrame, curState.ReferenceUp); } Rect screenRect3 = this.ScreenToFOV(this.HardGuideRect, num, fovH, curState.Lens.Aspect); if (!this.RotateToScreenBounds(ref curState, screenRect3, ref quaternion, num, fovH, -1f)) { this.RotateToScreenBounds(ref curState, screenRect, ref quaternion, num, fovH, deltaTime); } } this.m_CameraPosPrevFrame = curState.CorrectedPosition; this.m_LookAtPrevFrame = this.TrackedPoint; this.m_CameraOrientationPrevFrame = quaternion.Normalized(); this.m_ScreenOffsetPrevFrame = this.m_CameraOrientationPrevFrame.GetCameraRotationToTarget(this.m_LookAtPrevFrame - curState.CorrectedPosition, curState.ReferenceUp); curState.RawOrientation = this.m_CameraOrientationPrevFrame; }
/// <summary>Applies the composer rules and orients the camera accordingly</summary> /// <param name="curState">The current camera state</param> /// <param name="deltaTime">Used for calculating damping. If less than /// zero, then target will snap to the center of the dead zone.</param> public override void MutateCameraState(ref CameraState curState, float deltaTime) { // Initialize the state for previous frame if appropriate if (deltaTime < 0) { m_Predictor.Reset(); } if (!IsValid || !curState.HasLookAt) { return; } float targetDistance = (TrackedPoint - curState.CorrectedPosition).magnitude; if (targetDistance < Epsilon) { if (deltaTime >= 0) { curState.RawOrientation = m_CameraOrientationPrevFrame; } return; // navel-gazing, get outa here } // Expensive FOV calculations mCache.UpdateCache(curState.Lens, SoftGuideRect, HardGuideRect, targetDistance); Quaternion rigOrientation = curState.RawOrientation; if (deltaTime < 0) { // No damping, just snap to central bounds, skipping the soft zone Rect rect = mCache.mFovSoftGuideRect; if (m_CenterOnActivate) { rect = new Rect(rect.center, Vector2.zero); // Force to center } RotateToScreenBounds(ref curState, rect, ref rigOrientation, mCache.mFov, mCache.mFovH, -1); } else { // Start with previous frame's orientation (but with current up) Vector3 dir = m_LookAtPrevFrame - (m_CameraPosPrevFrame + curState.PositionDampingBypass); if (dir.AlmostZero()) { rigOrientation = Quaternion.LookRotation( m_CameraOrientationPrevFrame * Vector3.forward, curState.ReferenceUp); } else { rigOrientation = Quaternion.LookRotation(dir, curState.ReferenceUp); rigOrientation = rigOrientation.ApplyCameraRotation( -m_ScreenOffsetPrevFrame, curState.ReferenceUp); } // First force the previous rotation into the hard bounds, no damping, // then Now move it through the soft zone, with damping if (!RotateToScreenBounds(ref curState, mCache.mFovHardGuideRect, ref rigOrientation, mCache.mFov, mCache.mFovH, -1)) { RotateToScreenBounds(ref curState, mCache.mFovSoftGuideRect, ref rigOrientation, mCache.mFov, mCache.mFovH, deltaTime); } } m_CameraPosPrevFrame = curState.CorrectedPosition; m_LookAtPrevFrame = TrackedPoint; m_CameraOrientationPrevFrame = UnityQuaternionExtensions.Normalized(rigOrientation); m_ScreenOffsetPrevFrame = m_CameraOrientationPrevFrame.GetCameraRotationToTarget( m_LookAtPrevFrame - curState.CorrectedPosition, curState.ReferenceUp); curState.RawOrientation = m_CameraOrientationPrevFrame; }