7 static const float CONST_UD_MIN = -89.0;
8 static const float CONST_UD_MAX = 89.0;
10 static const float CONST_LR_MIN = -160.0;
11 static const float CONST_LR_MAX = 160.0;
13 static const float CONST_TRANSLATIONZ_MIN = -0.1;
16 private static bool s_bDebugRegistered;
24 m_iHandBoneIndex =
m_OwnerCharacter.GetAnimation().GetBoneIndex(
"righthandprop");
26 m_fFreelookFOV = GetBaseFOV();
29 m_AimingComponent = CharacterAimingComponent.Cast(
m_OwnerCharacter.FindComponent(CharacterAimingComponent));
30 m_OffsetLS =
"0.0 0.03 -0.07";
33 if (!s_bDebugRegistered) {
34 DiagMenu.RegisterRange(
SCR_DebugMenuID.DEBUGUI_CHARACTER_ADS_CAMERA,
"",
"ADS Camera",
"Character",
"0, 3, 0, 1");
35 s_bDebugRegistered =
true;
43 override void OnDeactivate(ScriptedCameraItem pNextCamera)
49 override void OnBlendIn()
58 override void OnBlendOut()
67 protected float GetSightsADSActivationPercentage()
69 if (m_LastWeaponComponent)
74 BaseSightsComponent optics = m_LastWeaponComponent.GetSights();
76 return optics.GetADSActivationPercentage();
83 protected float GetSightsADSDeactivationPercentage()
85 if (m_LastWeaponComponent)
90 BaseSightsComponent optics = m_LastWeaponComponent.GetSights();
92 return optics.GetADSDeactivationPercentage();
99 protected void OnBlendingIn(
float blendAlpha)
103 if (m_LastWeaponComponent && currentWeapon != m_LastWeaponComponent && m_LastWeaponComponent.IsSightADSActive())
104 m_LastWeaponComponent.SightADSDeactivated();
106 m_LastWeaponComponent = currentWeapon;
108 if (blendAlpha < GetSightsADSActivationPercentage())
111 if (currentWeapon && !currentWeapon.IsSightADSActive())
112 currentWeapon.SightADSActivated();
116 protected void OnBlendingOut(
float blendAlpha)
120 if (m_LastWeaponComponent && currentWeapon != m_LastWeaponComponent && m_LastWeaponComponent.IsSightADSActive())
121 m_LastWeaponComponent.SightADSDeactivated();
123 m_LastWeaponComponent = currentWeapon;
125 if (blendAlpha < GetSightsADSDeactivationPercentage())
128 if (currentWeapon && currentWeapon.IsSightADSActive())
129 currentWeapon.SightADSDeactivated();
131 CameraManager cameraMgr =
GetGame().GetCameraManager();
133 cameraMgr.SetOverlayCamera(
null);
137 override void OnActivate(ScriptedCameraItem pPrevCamera, ScriptedCameraItemResult pPrevCameraResult)
139 super.OnActivate(pPrevCamera, pPrevCameraResult);
142 vector f = pPrevCamera.GetBaseAngles();
144 m_fLeftRightAngle = f[1];
147 m_fStabilizerAlpha = 0.0;
148 m_fStabilizerAlphaVel = 0.0;
149 m_lastStablePos =
"0 0 0";
152 m_LastSightsComponent =
null;
153 m_bLastSightsBlend =
false;
154 m_fLastSightsBlendTime = 0;
158 protected void SolveCameraHeadAttach(
ADSCameraData cameraData, out ScriptedCameraItemResult pOutResult)
162 cameraData.m_vLookAngles[1] = Math.Clamp(cameraData.m_vLookAngles[1] + parentPitch, CONST_UD_MIN, CONST_UD_MAX);
164 vector headMatrix[4];
165 m_OwnerCharacter.GetAnimation().GetBoneMatrix(GetCameraBoneIndex(), headMatrix);
168 vector sightsRelativeMatrix[4];
169 Math3D.MatrixInvMultiply4(headMatrix, cameraData.m_mSightsLocalMat, sightsRelativeMatrix);
173 if (m_AimingComponent)
174 recoilPortion = Math.Clamp(m_AimingComponent.GetRawAimingTranslation()[2] * cameraData.m_fCamRecoilAmount, -CAMERA_RECOIL_LIMIT, CAMERA_RECOIL_LIMIT);
177 vector headPlane = cameraData.m_vSightsOffset;
178 headPlane[2] = headPlane[2] - recoilPortion;
181 Math3D.AnglesToMatrix(cameraData.m_vLookAngles, pOutResult.m_CameraTM);
184 vector resultPosition =
SCR_Math3D.IntersectPlane(sightsRelativeMatrix[3], -sightsRelativeMatrix[2], headPlane, vector.Forward);
187 pOutResult.m_CameraTM[3] = resultPosition;
188 pOutResult.m_fFOV = cameraData.m_fFOV;
189 pOutResult.m_fDistance = 0;
190 pOutResult.m_fNearPlane = 0.0125;
191 pOutResult.m_bAllowInterpolation =
true;
192 pOutResult.m_bUpdateWhenBlendOut =
true;
193 pOutResult.m_iDirectBone = GetCameraBoneIndex();
194 pOutResult.m_iDirectBoneMode = EDirectBoneMode.RelativePosition;
200 protected void SolveNewMethod(
ADSCameraData cameraData, out ScriptedCameraItemResult pOutResult,
float pDt,
bool allowInterpolation)
205 vector propBoneMS[4];
206 anim.GetBoneMatrix(m_iHandBoneIndex, propBoneMS);
216 Math3D.MatrixMultiply4(cameraData.m_mSightsLocalMat, zeroingLS,cameraData.m_mSightsLocalMat);
221 Math3D.MatrixInvMultiply4(propBoneMS, cameraData.m_mSightsLocalMat, sightsMS);
224 float targetFOV = cameraData.m_fFOV;
229 BaseSightsComponent currentSights =
m_WeaponManager.GetCurrentSights();
232 if (!m_LastSightsComponent && currentSights)
234 Math3D.MatrixCopy(sightsMS, m_vLastSightMS);
235 Math3D.MatrixCopy(sightsMS, m_vLastSightStMS);
238 m_LastSightsComponent = currentSights;
239 m_bLastSightsBlend =
false;
240 m_fLastSightsBlendTime = 0;
242 else if (m_LastSightsComponent != currentSights)
244 Math3D.MatrixCopy(m_vLastSightMS, m_vLastSightStMS);
245 m_fLastSightStFOV = m_fLastSightFOV;
246 m_LastSightsComponent = currentSights;
247 m_bLastSightsBlend =
true;
248 m_fLastSightsBlendTime = 0;
253 if (m_bLastSightsBlend)
256 if (m_fLastSightsBlendDuration < 0)
258 m_fLastSightsBlendTime = 0;
259 m_bLastSightsBlend =
false;
263 float alpha = m_fLastSightsBlendTime / m_fLastSightsBlendDuration;
267 m_fLastSightsBlendTime = 0;
268 m_bLastSightsBlend =
false;
272 vector interpBuffer[4];
277 Math3D.MatrixToQuat(m_vLastSightStMS, qb);
278 Math3D.MatrixToQuat(sightsMS, qt);
279 Math3D.QuatLerp(qb, qb, qt, alpha);
280 Math3D.QuatToMatrix(qb, interpBuffer);
283 interpBuffer[3] = vector.Lerp(m_vLastSightStMS[3], sightsMS[3], alpha);
286 Math3D.MatrixCopy(interpBuffer, sightsMS);
287 targetFOV = Math.Lerp(m_fLastSightStFOV, cameraData.m_fFOV, alpha);
290 m_fLastSightsBlendTime += pDt;
297 Math3D.MatrixCopy(sightsMS, m_vLastSightMS);
299 m_fLastSightFOV = targetFOV;
302 Math3D.MatrixMultiply4(propBoneMS, sightsMS, sightsMS);
305 vector cameraBoneMS[4];
306 anim.GetBoneMatrix(GetCameraBoneIndex(), cameraBoneMS);
312 if (m_lastStablePos == vector.Zero)
314 m_lastStablePos = cameraBoneMS[3];
323 vector pureSightsFwd = sightsMS[2];
325 vector projectedPosMS =
SCR_Math3D.IntersectPlane(sightsMS[3], -sightsMS[2], cameraBoneMS[3], cameraBoneMS[2]);
326 vector projToSightMS = projectedPosMS - sightsMS[3];
327 vector projToSightsDirMS = projToSightMS.Normalized();
331 vector aimingTranslationWeaponLS = m_AimingComponent.GetRawAimingTranslation();
334 vector aimingTranslationMS;
335 for (
int i = 0; i < 3; i++)
336 aimingTranslationMS += aimingTranslationWeaponLS[i] * sightsMS[i];
342 if (m_AimingComponent)
343 recoilPortion = Math.Clamp(aimingTranslationWeaponLS[2] * cameraData.m_fCamRecoilAmount, -CAMERA_RECOIL_LIMIT, CAMERA_RECOIL_LIMIT);
344 vector extraTranslation = recoilPortion * sightsMS[2];
347 sightsMS[3] = sightsMS[3] - aimingTranslationMS - extraTranslation;
352 vector aimingAnglesMS = cameraData.m_vLookAngles;
353 aimingAnglesMS[1] = aimingAnglesMS[1] +
m_OwnerCharacter.GetLocalYawPitchRoll()[1];
356 Math3D.AnglesToMatrix(aimingAnglesMS, sightsMS);
358 const float alphaEpsilon = 0.0005;
360 vector resultPosition = sightsMS[3];
361 bool isUnstable =
false;
374 if (m_iJumpAnimTagId != -1)
377 if (animComponent && animComponent.IsPrimaryTag(m_iJumpAnimTagId))
384 if (sm_TagADSTransitionOut != -1)
390 if (animComponent.IsPrimaryTag(sm_TagADSTransitionOut))
394 if (sm_TagADSTransitionIn != -1 && animComponent.IsPrimaryTag(sm_TagADSTransitionIn))
395 anim.GetBoneMatrix(sm_iCameraBoneIndex, cameraBoneMS);
397 m_lastStablePos = cameraBoneMS[3];
406 m_fStabilizerAlpha = Math.SmoothCD(m_fStabilizerAlpha, 1.0, m_fStabilizerAlphaVel, 0.1, 1000, pDt);
407 resultPosition = m_lastStablePos;
411 m_fStabilizerAlpha = Math.SmoothCD(m_fStabilizerAlpha, 0.0, m_fStabilizerAlphaVel, 0.1, 1000, pDt);
415 float lerpToCameraT = Math.Max(m_fStabilizerAlpha, obstructedAlpha);
416 bool shouldStabilize = lerpToCameraT > alphaEpsilon;
419 resultPosition = vector.Lerp(resultPosition, cameraBoneMS[3], lerpToCameraT);
422 if (!isUnstable && obstructedAlpha < alphaEpsilon)
424 m_lastStablePos = resultPosition;
429 if (cameraData.m_bFreeLook || m_fFreelookBlendAlpha > alphaEpsilon)
431 vector weaponAimingDir = m_AimingComponent.GetAimingRotation().AnglesToVector();
432 vector lookAimingDir = aimingAnglesMS.AnglesToVector();
433 float blendAlpha = 1.0 - (vector.Dot(weaponAimingDir, lookAimingDir) + 1.0) * 0.5;
434 const float blendOutSpeed = 3.0;
436 if (cameraData.m_bFreeLook)
437 m_fFreelookBlendAlpha = Math.Clamp(Math.Sqrt(blendAlpha * blendOutSpeed), 0.0, 1.0);
438 else m_fFreelookBlendAlpha -= pDt * 5.0;
440 if (m_fFreelookBlendAlpha <= alphaEpsilon)
441 m_fFreelookBlendAlpha = 0.0;
444 vector offset = m_OffsetLS;
445 vector additiveRotation =
"0 0 0";
446 m_CharacterHeadAimingComponent.GetLookTransformationLS(GetCameraBoneIndex(), EDirectBoneMode.RelativePosition, offset, additiveRotation, mat);
447 Math3D.MatrixMultiply4(cameraBoneMS, mat, mat);
448 vector goal = mat[3] +
"0 0.035 -0.045";
449 resultPosition = vector.Lerp(resultPosition, goal, m_fFreelookBlendAlpha);
453 float resultNegativeZ = resultPosition[2] - cameraBoneMS[3][2];
454 if (resultNegativeZ < 0)
456 sightsMS[3] = resultPosition + (-resultNegativeZ * pureSightsFwd[2] * pureSightsFwd);
460 sightsMS[3] = resultPosition;
464 if (!shouldStabilize)
466 Math3D.MatrixInvMultiply4(propBoneMS, sightsMS, pOutResult.m_CameraTM);
467 pOutResult.m_iDirectBone = m_iHandBoneIndex;
468 pOutResult.m_iDirectBoneMode = EDirectBoneMode.RelativeTransform;
476 pOutResult.m_iDirectBone = m_iHandBoneIndex;
477 pOutResult.m_iDirectBoneMode = EDirectBoneMode.RelativeTransform;
478 pOutResult.m_CameraTM[3] = sightsMS[3];
479 Math3D.AnglesToMatrix(aimingAnglesMS, pOutResult.m_CameraTM);
481 m_OwnerCharacter.GetAnimation().GetBoneMatrix(pOutResult.m_iDirectBone, directTM);
482 Math3D.MatrixInvMultiply4(directTM, pOutResult.m_CameraTM, pOutResult.m_CameraTM);
485 pOutResult.m_fFOV = Math.Lerp(targetFOV, GetBaseFOV(), m_fFreelookBlendAlpha);
486 pOutResult.m_fDistance = 0;
487 pOutResult.m_fNearPlane = 0.0125;
488 pOutResult.m_bAllowInterpolation = allowInterpolation;
489 pOutResult.m_fUseHeading = 1.0;
490 pOutResult.m_bUpdateWhenBlendOut =
true;
491 pOutResult.m_fPositionModelSpace = 0.0;
493 m_bWasStabilizedLastFrame = shouldStabilize;
499 protected void SolveCameraHandAttach(
ADSCameraData cameraData, out ScriptedCameraItemResult pOutResult,
float pDt,
bool allowInterpolation)
505 cameraData.m_vLookAngles[1] = Math.Clamp(cameraData.m_vLookAngles[1] + parentPitch, CONST_UD_MIN, CONST_UD_MAX);
507 vector headMatrix[4];
508 anim.GetBoneMatrix(GetCameraBoneIndex(), headMatrix);
511 vector sightsRelativeMatrix[4];
512 Math3D.MatrixInvMultiply4(headMatrix, cameraData.m_mSightsLocalMat, sightsRelativeMatrix);
516 if (m_AimingComponent)
517 recoilPortion = Math.Clamp(m_AimingComponent.GetRawAimingTranslation()[2] * cameraData.m_fCamRecoilAmount, -CAMERA_RECOIL_LIMIT, CAMERA_RECOIL_LIMIT);
520 vector headPlane = cameraData.m_vSightsOffset;
521 headPlane[2] = headPlane[2] - recoilPortion;
524 vector resultPosition =
SCR_Math3D.IntersectPlane(sightsRelativeMatrix[3], -sightsRelativeMatrix[2], headPlane, vector.Forward);
527 vector handMatrix[4];
528 anim.GetBoneMatrix(m_iHandBoneIndex, handMatrix);
531 vector relativeSightsMatrix[4];
533 Math3D.MatrixInvMultiply4(handMatrix, cameraData.m_mSightsLocalMat, relativeSightsMatrix);
536 Math3D.AnglesToMatrix(cameraData.m_vLookAngles, pOutResult.m_CameraTM);
538 bool isUnstable =
false;
549 m_fStabilizerAlpha = Math.SmoothCD(m_fStabilizerAlpha, 1.0, m_fStabilizerAlphaVel, 0.14, 1000, pDt);
550 resultPosition = m_lastStablePos;
554 m_fStabilizerAlpha = Math.SmoothCD(m_fStabilizerAlpha, 0.0, m_fStabilizerAlphaVel, 0.14, 1000, pDt);
559 if (m_fStabilizerAlpha > 0 || obstructedAlpha > 0)
561 float t = Math.Max(m_fStabilizerAlpha, obstructedAlpha);
562 vector headRelativePosition =
"0 0 0";
563 resultPosition = vector.Lerp(resultPosition, headRelativePosition, t);
566 if (!isUnstable && obstructedAlpha < 0.001)
568 m_lastStablePos = resultPosition;
572 resultPosition = resultPosition.Multiply4(headMatrix);
573 resultPosition = resultPosition.InvMultiply4(handMatrix);
577 pOutResult.m_CameraTM[3] = resultPosition;
578 pOutResult.m_fFOV = cameraData.m_fFOV;
579 pOutResult.m_fDistance = 0;
580 pOutResult.m_fNearPlane = 0.0125;
581 pOutResult.m_bAllowInterpolation = allowInterpolation;
582 pOutResult.m_bUpdateWhenBlendOut =
true;
583 pOutResult.m_iDirectBone = m_iHandBoneIndex;
584 pOutResult.m_iDirectBoneMode = EDirectBoneMode.RelativePosition;
585 pOutResult.m_fPositionModelSpace = 0.0;
589 protected void SolveCamera2DSight(
ADSCameraData cameraData, out ScriptedCameraItemResult pOutResult)
593 m_WeaponManager.GetCurrentSightsCameraTransform(cameraData.m_mSightsLocalMat, targetFOV);
601 if (sights2D && weapon && weapon.IsSightADSActive())
603 vector sightsOffset = sights2D.GetSightsFrontPosition(
true) + sights2D.GetCameraOffset() - sights2D.GetSightsOffset();
604 vector cameraOffset = sightsOffset.Multiply3(cameraData.m_mSightsLocalMat);
605 cameraData.m_mSightsLocalMat[3] = cameraData.m_mSightsLocalMat[3] + cameraOffset;
610 sights2D.GetSightsTransform(sightMat,
true);
613 sights2D.GetOwner().GetWorldTransform(ownerMat);
614 Math3D.MatrixMultiply3(ownerMat, sightMat, sightMat);
618 sights2D.GetCameraLocalTransform(opticMat);
619 Math3D.MatrixMultiply3(ownerMat, opticMat, opticMat);
623 Math3D.MatrixInvMultiply3(opticMat, sightMat, cameraMat);
625 cameraAngles = Math3D.MatrixToAngles(cameraMat);
628 SCR_2DPIPSightsComponent sightsPIP = SCR_2DPIPSightsComponent.Cast(sights2D);
630 targetFOV = sightsPIP.GetMainCameraFOV();
633 pOutResult.m_fFOV = Math.Min(GetBaseFOV(), targetFOV);
636 vector adjustedLookAngles = cameraData.m_vLookAngles;
642 adjustedLookAngles = aiming.GetAimingRotation();
645 vector offset = aiming.GetModifiedAimingTranslation() * pOutResult.m_fFOV;
646 adjustedLookAngles = adjustedLookAngles + Vector(offset[1], offset[2], 0);
652 adjustedLookAngles = adjustedLookAngles - cameraAngles;
653 Math3D.AnglesToMatrix(adjustedLookAngles, lookRot);
656 vector handBoneTM[4];
657 m_OwnerCharacter.GetAnimation().GetBoneMatrix(m_iHandBoneIndex, handBoneTM);
660 Math3D.MatrixInvMultiply4(handBoneTM, cameraData.m_mSightsLocalMat, pOutResult.m_CameraTM);
661 vector finalPos = pOutResult.m_CameraTM[3];
664 vector viewMatHandRel[4];
665 Math3D.MatrixInvMultiply4(handBoneTM, lookRot, pOutResult.m_CameraTM);
668 pOutResult.m_CameraTM[3] = finalPos;
671 pOutResult.m_iDirectBone = m_iHandBoneIndex;
672 pOutResult.m_iDirectBoneMode = EDirectBoneMode.RelativeTransform;
673 pOutResult.m_bUpdateWhenBlendOut =
true;
674 pOutResult.m_fDistance = 0;
675 pOutResult.m_fUseHeading = 0;
676 pOutResult.m_fNearPlane = 0.025;
677 pOutResult.m_bBlendFOV =
true;
681 override void OnUpdate(
float pDt, out ScriptedCameraItemResult pOutResult)
693 bool canFreelook = sights && sights.CanFreelook();
695 m_fFreelookFOV = GetBaseFOV();
697 pOutResult.m_vBaseAngles = GetBaseAngles();
701 vector lookAngles = m_CharacterHeadAimingComponent.GetLookAngles();
704 lookAngles[0] = m_CommandWeapons.GetAimAngleLR();
705 lookAngles[1] = m_CommandWeapons.GetAimAngleUD();
709 m_pCameraData.m_fDeltaTime = pDt;
710 m_pCameraData.m_vLookAngles = lookAngles;
711 m_pCameraData.m_fFOV = GetBaseFOV();
716 m_WeaponManager.GetCurrentSightsCameraTransform(m_pCameraData.m_mSightsLocalMat, m_pCameraData.m_fFOV);
717 m_pCameraData.m_vSightsOffset = sights.GetSightsOffset();
718 m_pCameraData.m_fCamRecoilAmount = sights.GetCameraRecoilAmount();
722 Math3D.MatrixIdentity4(m_pCameraData.m_mSightsLocalMat);
726 m_pCameraData.m_fFOV = Math.Min(GetBaseFOV(), m_pCameraData.m_fFOV);
733 vector zeroingMatrix[4];
734 if (currentWeapon.GetCurrentSightsZeroingTransform(zeroingMatrix))
737 zeroingMatrix[3] = -zeroingMatrix[3];
738 Math3D.MatrixMultiply4(m_pCameraData.m_mSightsLocalMat, zeroingMatrix, m_pCameraData.m_mSightsLocalMat);
743 CameraBase overlayCamera;
750 auto pip = SCR_2DPIPSightsComponent.Cast(sights2d);
754 SolveCamera2DSight(m_pCameraData, pOutResult);
756 pOutResult.m_pWSAttachmentReference =
null;
761 m_pCameraData.m_fFOV = pip.GetMainCameraFOV();
762 overlayCamera = pip.GetPIPCamera();
767 m_pCameraData.m_vLookAngles[0] = 0.0;
771 m_pCameraData.m_bFreeLook = canFreelook && (
m_ControllerComponent.IsFreeLookEnabled() || m_bForceFreeLook);
774 int solveMethod = DiagMenu.GetValue(
SCR_DebugMenuID.DEBUGUI_CHARACTER_ADS_CAMERA);
776 if (solveMethod == 1)
777 SolveCameraHandAttach(m_pCameraData, pOutResult, pDt,
false);
778 else if (solveMethod == 2)
779 SolveCameraHeadAttach(m_pCameraData, pOutResult);
780 else if (solveMethod == 3)
781 SolveCameraHandAttach(m_pCameraData, pOutResult, pDt,
true);
783 SolveNewMethod(m_pCameraData, pOutResult, pDt,
true);
785 SolveNewMethod(m_pCameraData, pOutResult, pDt,
true);
788 CameraManager cameraMgr =
GetGame().GetCameraManager();
789 if (cameraMgr !=
null)
792 if (m_pCameraData.m_bFreeLook)
795 cameraMgr.SetOverlayCamera(
null);
797 else if (overlayCamera)
800 cameraMgr.SetOverlayCamera(overlayCamera);
805 pOutResult.m_pWSAttachmentReference =
null;
808 if (m_CharacterCameraHandler)
809 m_CharacterCameraHandler.AddShakeToToTransform(pOutResult.m_CameraTM, pOutResult.m_fFOV);
815 protected CharacterAimingComponent m_AimingComponent;
816 protected BaseSightsComponent m_BinocularSight;
817 protected BaseSightsComponent m_LastSightsComponent;
818 protected vector m_vLastSightMS[4];
819 protected vector m_vLastSightStMS[4];
820 protected float m_fLastSightFOV;
821 protected float m_fLastSightStFOV;
822 protected bool m_bLastSightsBlend;
823 protected float m_fLastSightsBlendTime;
824 protected float m_fLastSightsBlendDuration = 0.15;
827 protected int m_iHandBoneIndex;
829 protected AnimationTagID m_iJumpAnimTagId;
830 protected vector m_OffsetLS;
831 protected float m_fADSToFPSDeg;
832 protected float m_fFreelookFOV;
833 protected vector m_lastStablePos;
835 protected float m_fStabilizerAlpha = 0.0;
836 protected float m_fStabilizerAlphaVel = 0.0;
838 protected bool m_bWasStabilizedLastFrame =
false;
840 protected float m_fFreelookBlendAlpha;
842 private vector m_vLastEndPos;
844 protected const float CAMERA_INTERP = 0.6;
845 protected const float CAMERA_RECOIL_LIMIT = 0.25;