cameraShaker.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #pragma once
  2. #include <rendering/camera.h>
  3. #include <iostream>
  4. struct CameraShaker
  5. {
  6. // Configuration constants (tweak these values)
  7. constexpr static float walkShakeFrequency = 14.0f; // oscillation frequency for steps
  8. constexpr static float walkShakeAmplitude = 0.001f; // bobbing amplitude
  9. constexpr static float hitShakeAmplitude = 0.05f; // impulse shake on hit
  10. constexpr static float hitShakeDuration = 0.2f; // how long the hit impulse lasts (seconds)
  11. constexpr static float fovSpeedThreshold = 0.1f; // speed above which FOV is modified
  12. constexpr static float fovChangeFactor = 0.05f; // how much extra speed adds to FOV change
  13. constexpr static float fovMaxChange = 0.3f; // maximum FOV change
  14. constexpr static float fallTiltMultiplier = 0.5f; // how much falling affects the tilt
  15. constexpr static float lateralTiltMultiplier = 0.01f; // how much lateral movement tilts the view
  16. constexpr static float damping = 5.0f; // general damping factor for smoothing
  17. // Internal state variables
  18. float timeAccumulator = 0.0f; // accumulates time for sine functions
  19. float hitShakeTimer = 0.0f; // countdown timer for hit impulse
  20. glm::vec3 positionOffset = glm::vec3(0.0f); // accumulated positional shake
  21. glm::vec3 upOffset = glm::vec3(0.0f); // additional up vector modification
  22. float fovOffset = 0.0f; // accumulated FOV change
  23. glm::vec3 viewDirOffset = glm::vec3(0.0f); // offset for the view direction
  24. // Keep track of previous state (could be used to detect rapid stops)
  25. glm::vec3 prevInputMovement = glm::vec3(0.0f);
  26. glm::vec3 prevRealMovement = glm::vec3(0.0f);
  27. // Public variables that will be applied to the camera
  28. glm::vec3 up = {0.f,1.f,0.f};
  29. float fovChange = 0.0f;
  30. glm::vec3 position = glm::vec3(0.0f);
  31. glm::vec3 viewDirection = {0.f,0.f,-1.f};
  32. float realSpeedLast1 = 0;
  33. float realSpeedLast2 = 0;
  34. float realSpeedLast3 = 0;
  35. float realSpeedLast4 = 0;
  36. // Helper function: returns a random float in [0,1]
  37. float randFloat()
  38. {
  39. return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
  40. }
  41. void updateCameraShake(float deltaTime, glm::vec3 inputMovement, glm::vec3 realMovement, bool wasJustHit)
  42. {
  43. // Update time accumulator (for smooth oscillation)
  44. timeAccumulator += deltaTime;
  45. // Apply damping to all offsets so they gradually settle
  46. float damp = glm::clamp(1.0f - damping * deltaTime, 0.0f, 1.0f);
  47. positionOffset *= damp;
  48. upOffset *= damp;
  49. viewDirOffset *= damp;
  50. // ---------------------------
  51. // 1. Hit impulse shake
  52. // ---------------------------
  53. if (wasJustHit)
  54. {
  55. // Restart the hit shake timer
  56. hitShakeTimer = hitShakeDuration;
  57. }
  58. if (hitShakeTimer > 0.0f)
  59. {
  60. // Compute an impulse factor that decays over the hit duration
  61. float impulseFactor = hitShakeAmplitude * (hitShakeTimer / hitShakeDuration);
  62. // Add a random offset to simulate a jolt (position and view direction)
  63. positionOffset += glm::vec3(
  64. impulseFactor * (randFloat() - 0.5f),
  65. impulseFactor * (randFloat() - 0.5f),
  66. impulseFactor * (randFloat() - 0.5f)
  67. );
  68. viewDirOffset += glm::vec3(
  69. impulseFactor * (randFloat() - 0.5f),
  70. impulseFactor * (randFloat() - 0.5f),
  71. 0.0f // avoid messing too much with depth
  72. );
  73. hitShakeTimer -= deltaTime;
  74. }
  75. // ---------------------------
  76. // 2. Walking bob (wobble shake)
  77. // ---------------------------
  78. float inputSpeed = glm::length(inputMovement);
  79. if (inputSpeed > 0.01f)
  80. {
  81. inputSpeed = glm::clamp(inputSpeed, 5.f, 20.f);
  82. float walkSpeed = glm::clamp((inputSpeed / 14.f), 1.f, 2.5f);
  83. //TODO INCREASE THE SHAKE SPEED WITH SPEED
  84. // Sine oscillation for bobbing (vertical motion)
  85. float bob = sin(timeAccumulator * walkShakeFrequency * walkSpeed) * walkShakeAmplitude * inputSpeed;
  86. float bobx = sin(timeAccumulator * walkShakeFrequency * walkSpeed * 0.5 + 3.14) * walkShakeAmplitude * inputSpeed * 0.65;
  87. positionOffset.y += bob;
  88. positionOffset.x += bobx;
  89. // Slight lateral tilt based on the horizontal (x) input
  90. //upOffset.x -= inputMovement.x * 0.01f;
  91. //upOffset.x = glm::clamp(upOffset.x, -0.2f, 0.2f);
  92. //upOffset.x = glm::clamp(upOffset.x, -0.2f * inputMovement.x * 0.09f, 0.2f * inputMovement.x * 0.09f);
  93. }
  94. // ---------------------------
  95. // 3. Dynamic FOV change at high speeds
  96. // ---------------------------
  97. realMovement *= 100.f;
  98. float realSpeed = glm::length(realMovement);
  99. float avgRealSpeed = std::max({realSpeed, realSpeedLast1, realSpeedLast2, realSpeedLast3, realSpeedLast4});
  100. realSpeedLast4 = realSpeedLast3;
  101. realSpeedLast3 = realSpeedLast2;
  102. realSpeedLast2 = realSpeedLast1;
  103. realSpeedLast1 = realSpeed;
  104. #pragma region fov
  105. if(0)
  106. {
  107. //std::cout << avgRealSpeed << " ";
  108. //if(0)
  109. float desiredFov = 0;
  110. if (avgRealSpeed > fovSpeedThreshold)
  111. {
  112. //float excessSpeed = avgRealSpeed - fovSpeedThreshold;
  113. //desiredFov = glm::min(excessSpeed * 0.05f, fovMaxChange);
  114. //desiredFov = fovMaxChange / 2.f;
  115. desiredFov = fovMaxChange;
  116. }
  117. //if (avgRealSpeed > fovSpeedThreshold * 2)
  118. //{
  119. // desiredFov = fovMaxChange / 1.5f;
  120. //}
  121. //
  122. //if (avgRealSpeed > fovSpeedThreshold * 4)
  123. //{
  124. // desiredFov = fovMaxChange / 1;
  125. //}
  126. //if (avgRealSpeed > fovSpeedThreshold)
  127. //{
  128. // float excessSpeed = avgRealSpeed - fovSpeedThreshold;
  129. // fovOffset += excessSpeed * fovChangeFactor;
  130. // fovOffset = glm::min(fovOffset, fovMaxChange);
  131. // //fovOffset = glm::min(fovOffset, excessSpeed);
  132. //}
  133. //else
  134. //{
  135. // fovOffset *= damp;
  136. //}
  137. //desiredFov = 0;
  138. if (desiredFov == 0)
  139. {
  140. fovOffset *= damp;
  141. }
  142. else
  143. {
  144. if (desiredFov > fovOffset)
  145. {
  146. fovOffset += deltaTime;
  147. if (fovOffset > desiredFov) { fovOffset = desiredFov; }
  148. }
  149. else if (desiredFov < fovOffset)
  150. {
  151. fovOffset -= deltaTime;
  152. if (fovOffset < desiredFov) { fovOffset = desiredFov; }
  153. }
  154. }
  155. }
  156. #pragma endregion
  157. // ---------------------------
  158. // 4. Falling and lateral tilting
  159. // ---------------------------
  160. if (0)
  161. if (realMovement.y < -0.1f) // when falling (negative y indicates downward movement)
  162. {
  163. // A tilt effect from falling (pitching the camera slightly downward)
  164. float fallTilt = -realMovement.y * fallTiltMultiplier;
  165. // Lateral movement causes a roll effect (tilting the camera left/right)
  166. float lateralTilt = realMovement.x * lateralTiltMultiplier;
  167. //viewDirOffset += glm::vec3(lateralTilt, fallTilt, 0.0f);
  168. upOffset += glm::vec3(lateralTilt, 0.f, 0.0f);
  169. }
  170. // ---------------------------
  171. // 5. Sudden stops / deceleration shake
  172. // ---------------------------
  173. // Compare current input to previous frame
  174. if (0)
  175. {
  176. glm::vec3 inputDelta = inputMovement * deltaTime - prevInputMovement;
  177. // If there is a significant drop in movement, add a subtle shake
  178. if (glm::length(inputDelta) < -0.5f)
  179. {
  180. positionOffset += glm::vec3(0.0f, -0.05f, 0.0f);
  181. }
  182. prevInputMovement = inputMovement;
  183. prevRealMovement = realMovement;
  184. }
  185. // ---------------------------
  186. // 6. Update the public variables
  187. // ---------------------------
  188. position = positionOffset;
  189. fovChange = fovOffset;
  190. // Compute the new up vector, adding the offset to the base (0,1,0) and normalizing.
  191. up = glm::normalize(glm::vec3(0.0f, 1.0f, 0.0f) + upOffset);
  192. // Update view direction: start from base (0,0,-1) and add any directional offsets.
  193. viewDirection = glm::normalize(glm::vec3(0.0f, 0.0f, -1.0f) + viewDirOffset);
  194. };
  195. void applyCameraShake(Camera &c)
  196. {
  197. c.up = up;
  198. c.fovRadians += fovChange;
  199. c.position += position;
  200. //c.viewDirection += viewDirection;
  201. //c.viewDirection = glm::normalize(c.viewDirection);
  202. if (fovChange == 0 && position == glm::vec3{} && up == glm::vec3(0, 1, 0))
  203. {
  204. timeAccumulator = 0;
  205. }
  206. };
  207. };