mirror of
https://github.com/izzy2lost/2ship2harkinian-Android.git
synced 2026-06-19 01:20:08 -07:00
Fix Camera Interpolation For Sudden Camera Changes (#479)
* Fix Camera Interpolation On Sudden Movements * huge formatting discovery * increase angle tolerance
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
#include "CameraInterpolationFixes.h"
|
||||
#include <libultraship/bridge.h>
|
||||
#include "Enhancements/GameInteractor/GameInteractor.h"
|
||||
#include "CameraUtils.h"
|
||||
#include "Enhancements/FrameInterpolation/FrameInterpolation.h"
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
#include "macros.h"
|
||||
#include "functions.h"
|
||||
extern PlayState* gPlayState;
|
||||
extern SaveContext gSaveContext;
|
||||
extern CameraSetting sCameraSettings[];
|
||||
}
|
||||
|
||||
// This function should check for outstanding conditions which the distance check would falsly flag
|
||||
// as something we do not want to interpolate. This mostly applies to general play for now
|
||||
bool Camera_ShouldOverrideInterpolationCheck(Camera* camera) {
|
||||
switch (sCameraSettings[camera->setting].cameraModes[camera->mode].funcId) {
|
||||
case CAM_FUNC_BATTLE0:
|
||||
case CAM_FUNC_BATTLE1:
|
||||
case CAM_FUNC_BATTLE2:
|
||||
case CAM_FUNC_BATTLE3:
|
||||
case CAM_FUNC_BATTLE4:
|
||||
case CAM_FUNC_PARALLEL0:
|
||||
case CAM_FUNC_PARALLEL1:
|
||||
case CAM_FUNC_PARALLEL2:
|
||||
case CAM_FUNC_PARALLEL3:
|
||||
case CAM_FUNC_PARALLEL4:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function checks whether there is too large a distance or change in angle between the expected
|
||||
// position camera and the actual position of the camera. If there is, then we should not interpolate
|
||||
bool Camera_ShouldInterpolateDist(Camera* camera) {
|
||||
// Account for changes in position, pitch and yaw. Roll is rarely used so not currently handled
|
||||
// `Velocity` is measured as the change across the previous frame
|
||||
static f32 lastYaw = 0.0f;
|
||||
static f32 lastYawVelocity = 0.0f;
|
||||
static f32 lastPitch = 0.0f;
|
||||
static f32 lastPitchVelocity = 0.0f;
|
||||
static Vec3f lastEye = { 0.0f, 0.0f, 0.0f };
|
||||
static Vec3f lastEyeVelocity = { 0.0f, 0.0f, 0.0f };
|
||||
Vec3f* eye = &camera->eye;
|
||||
Vec3f* at = &camera->at;
|
||||
Vec3f eyeVelo;
|
||||
bool shouldInterpolate = true;
|
||||
VecGeo eyeGeo = OLib_Vec3fDiffToVecGeo(at, eye);
|
||||
Vec3f expectedEye;
|
||||
|
||||
// Calculate Current
|
||||
f32 yaw = BINANG_TO_DEG(eyeGeo.yaw);
|
||||
if (yaw > 360.0f) {
|
||||
yaw -= 360.0f;
|
||||
} else if (yaw < 0.0f) {
|
||||
yaw += 360.0f;
|
||||
}
|
||||
f32 yawVelocity = yaw - lastYaw;
|
||||
f32 pitch = BINANG_TO_DEG(eyeGeo.pitch);
|
||||
f32 pitchVelocity = pitch - lastPitch;
|
||||
Math_Vec3f_Diff(eye, &lastEye, &eyeVelo);
|
||||
|
||||
// Update static variables.
|
||||
lastYaw = yaw;
|
||||
lastYawVelocity = yawVelocity;
|
||||
lastPitch = pitch;
|
||||
lastPitchVelocity = pitchVelocity;
|
||||
lastEye = *eye;
|
||||
lastEyeVelocity = eyeVelo;
|
||||
|
||||
if (Camera_ShouldOverrideInterpolationCheck(camera)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate Expected
|
||||
f32 expectedYaw = lastYaw + lastYawVelocity;
|
||||
if (expectedYaw > 360.0f) {
|
||||
expectedYaw -= 360.0f;
|
||||
} else if (expectedYaw < 0.0f) {
|
||||
expectedYaw += 360.0f;
|
||||
}
|
||||
f32 expectedPitch = CLAMP(lastPitch + lastPitchVelocity, -180.0f, 180.0f);
|
||||
Math_Vec3f_Sum(&lastEye, &lastEyeVelocity, &expectedEye);
|
||||
|
||||
// Check if changes are too great
|
||||
f32 diffYaw = fabsf(yaw - expectedYaw);
|
||||
f32 diffPitch = fabsf(pitch - expectedPitch);
|
||||
f32 diffDistEye = Math_Vec3f_DistXYZ(eye, &expectedEye);
|
||||
|
||||
if ((diffYaw > 90.0f && diffYaw < 270.0f) || diffPitch > 60.0f || diffDistEye > 200.0f) {
|
||||
shouldInterpolate = false;
|
||||
}
|
||||
|
||||
// If we aren't interpolating, then reset velocities as they are inaccurate to the camera's current movement
|
||||
if (!shouldInterpolate) {
|
||||
lastYawVelocity = 0.0f;
|
||||
lastPitchVelocity = 0.0f;
|
||||
lastEyeVelocity = { 0.0f, 0.0f, 0.0f };
|
||||
}
|
||||
|
||||
return shouldInterpolate;
|
||||
}
|
||||
|
||||
void RegisterCameraInterpolationFixes() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::AfterCameraUpdate>(
|
||||
[](Camera* camera) { FrameInterpolation_ShouldInterpolateFrame(Camera_ShouldInterpolateDist(camera)); });
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CAMERA_INTERPOLATE_FIXES_H
|
||||
#define CAMERA_INTERPOLATE_FIXES_H
|
||||
|
||||
void RegisterCameraInterpolationFixes();
|
||||
|
||||
#endif // CAMERA_INTERPOLATE_FIXES_H
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
void InitEnhancements() {
|
||||
// Camera
|
||||
RegisterCameraInterpolationFixes();
|
||||
RegisterCameraFreeLook();
|
||||
RegisterDebugCam();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef ENHANCEMENTS_H
|
||||
#define ENHANCEMENTS_H
|
||||
|
||||
#include "Camera/CameraInterpolationFixes.h"
|
||||
#include "Camera/DebugCam.h"
|
||||
#include "Camera/FreeLook.h"
|
||||
#include "Cheats/MoonJump.h"
|
||||
|
||||
@@ -451,11 +451,23 @@ unordered_map<Mtx*, MtxF> FrameInterpolation_Interpolate(float step) {
|
||||
return ctx.mtx_replacements;
|
||||
}
|
||||
|
||||
bool camera_interpolation = false;
|
||||
|
||||
void FrameInterpolation_ShouldInterpolateFrame(bool shouldInterpolate) {
|
||||
camera_interpolation = shouldInterpolate;
|
||||
}
|
||||
|
||||
void FrameInterpolation_StartRecord(void) {
|
||||
previous_recording = move(current_recording);
|
||||
current_recording = {};
|
||||
current_path.clear();
|
||||
current_path.push_back(¤t_recording.root_path);
|
||||
if (!camera_interpolation) {
|
||||
// default to interpolating
|
||||
camera_interpolation = true;
|
||||
is_recording = false;
|
||||
return;
|
||||
}
|
||||
if (OTRGlobals::Instance->GetInterpolationFPS() != 20) {
|
||||
is_recording = true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ extern "C" {
|
||||
|
||||
#endif
|
||||
|
||||
void FrameInterpolation_ShouldInterpolateFrame(bool shouldInterpolate);
|
||||
|
||||
void FrameInterpolation_StartRecord(void);
|
||||
|
||||
void FrameInterpolation_StopRecord(void);
|
||||
|
||||
@@ -141,6 +141,21 @@ void GameInteractor_ExecuteOnCameraChangeModeFlags(Camera* camera) {
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnCameraChangeModeFlags>(camera);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteAfterCameraUpdate(Camera* camera) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::AfterCameraUpdate>(camera);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::AfterCameraUpdate>(camera->uid, camera);
|
||||
GameInteractor::Instance->ExecuteHooksForPtr<GameInteractor::AfterCameraUpdate>((uintptr_t)camera, camera);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::AfterCameraUpdate>(camera);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnCameraChangeSettingsFlags(Camera* camera) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnCameraChangeSettingsFlags>(camera);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnCameraChangeSettingsFlags>(camera->uid, camera);
|
||||
GameInteractor::Instance->ExecuteHooksForPtr<GameInteractor::OnCameraChangeSettingsFlags>((uintptr_t)camera,
|
||||
camera);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnCameraChangeSettingsFlags>(camera);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnPassPlayerInputs(Input* input) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPassPlayerInputs>(input);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnPassPlayerInputs>(input);
|
||||
|
||||
@@ -269,7 +269,9 @@ class GameInteractor {
|
||||
DEFINE_HOOK(OnFlagSet, (FlagType flagType, u32 flag));
|
||||
DEFINE_HOOK(OnFlagUnset, (FlagType flagType, u32 flag));
|
||||
|
||||
DEFINE_HOOK(AfterCameraUpdate, (Camera * camera));
|
||||
DEFINE_HOOK(OnCameraChangeModeFlags, (Camera * camera));
|
||||
DEFINE_HOOK(OnCameraChangeSettingsFlags, (Camera * camera));
|
||||
|
||||
DEFINE_HOOK(OnPassPlayerInputs, (Input * input));
|
||||
|
||||
@@ -308,7 +310,9 @@ void GameInteractor_ExecuteOnSceneFlagUnset(s16 sceneId, FlagType flagType, u32
|
||||
void GameInteractor_ExecuteOnFlagSet(FlagType flagType, u32 flag);
|
||||
void GameInteractor_ExecuteOnFlagUnset(FlagType flagType, u32 flag);
|
||||
|
||||
void GameInteractor_ExecuteAfterCameraUpdate(Camera* camera);
|
||||
void GameInteractor_ExecuteOnCameraChangeModeFlags(Camera* camera);
|
||||
void GameInteractor_ExecuteOnCameraChangeSettingsFlags(Camera* camera);
|
||||
|
||||
void GameInteractor_ExecuteOnPassPlayerInputs(Input* input);
|
||||
|
||||
|
||||
@@ -7635,6 +7635,8 @@ Vec3s Camera_Update(Camera* camera) {
|
||||
camera->inputDir.z = 0;
|
||||
}
|
||||
|
||||
GameInteractor_ExecuteAfterCameraUpdate(camera);
|
||||
|
||||
return camera->inputDir;
|
||||
}
|
||||
|
||||
@@ -7885,6 +7887,8 @@ s16 Camera_ChangeSettingFlags(Camera* camera, s16 setting, s16 flags) {
|
||||
|
||||
camera->setting = setting;
|
||||
|
||||
GameInteractor_ExecuteOnCameraChangeSettingsFlags(camera);
|
||||
|
||||
if (Camera_ChangeModeFlags(camera, camera->mode, true) >= 0) {
|
||||
Camera_ResetActionFuncState(camera, camera->mode);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user