Skip to content

Commit b455502

Browse files
committed
Fix camera jumps during cutscenes and events
Haven't got all camera cutscenes patched yet. But I think its still better then the previous behavior.
1 parent cf8fa2b commit b455502

File tree

4 files changed

+78
-33
lines changed

4 files changed

+78
-33
lines changed

resources/BreathOfTheWild_BetterVR/patch_FirstPersonMode_Events.asm

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,60 @@ moduleMatches = 0x6267BFD0
33

44
.origin = codecave
55

6+
7+
0x02C036E4 = act__getCamera:
8+
0x030EA2CC = ksys__act__ai__ActionBase__setFinished:
9+
10+
hook_calcCameraDuringEvent_trampoline:
11+
; at entry r3 = this+0x10 (arg for getCamera), LR = return addr in caller
12+
mflr r0
13+
stwu r1, -0x10(r1)
14+
stw r0, 0x14(r1)
15+
stw r3, 0x0C(r1)
16+
17+
; c++ hook decides whether to skip the event camera updates based on the current event's settings
18+
bla import.coreinit.hook_ShouldSkipEventCamera
19+
20+
cmpwi r3, 0
21+
bne skipEventCamera
22+
23+
; run regular camera update
24+
lwz r3, 0x0C(r1)
25+
lis r4, act__getCamera@ha
26+
addi r4, r4, act__getCamera@l
27+
mtctr r4
28+
bctrl
29+
b done_calcCameraDuringEvent_trampoline
30+
31+
skipEventCamera:
32+
; mark the action as finished so the game doesn't get stuck waiting for it, and return 0 to skip the camera update
33+
lwz r3, 0x0C(r1)
34+
addi r3, r3, -0x10 ; r3 = ActionBase this (getCamera arg was this+0x10)
35+
lis r4, ksys__act__ai__ActionBase__setFinished@ha
36+
addi r4, r4, ksys__act__ai__ActionBase__setFinished@l
37+
mtctr r4
38+
bctrl
39+
li r3, 0
40+
41+
done_calcCameraDuringEvent_trampoline:
42+
lwz r0, 0x14(r1)
43+
addi r1, r1, 0x10
44+
mtlr r0
45+
blr
46+
47+
; patch CameraEventAnim::m_43_calcCameraDuringEvent
48+
0x02BA3214 = bla hook_calcCameraDuringEvent_trampoline
49+
; patch CameraEventMovePos::m_43_calcCameraDuringEvent
50+
0x02BB9D30 = bla hook_calcCameraDuringEvent_trampoline
51+
; patch CameraEventMovePos::m_42_calcCameraDuringEvent
52+
0x02BB7034 = bla hook_calcCameraDuringEvent_trampoline
53+
; patch CameraEventMove::m_43_calcCameraDuringEvent
54+
0x02BB1F68 = bla hook_calcCameraDuringEvent_trampoline
55+
56+
57+
; --------------------------------------------------------------------------------------
58+
; run a function every frame to check the current event and update settings accordingly
59+
660
0x1046D3AC = EventMgr__sInstance:
761
0x031CA1C0 = EventMgr__getActiveEventName:
862

resources/BreathOfTheWild_BetterVR/patch_Misc.asm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ moduleMatches = 0x6267BFD0
33

44
.origin = codecave
55

6+
; disable sideOffsetBowCus
7+
;0x02C01A5C = bla import.coreinit.hook_OverwriteCameraParam
8+
69
; disable agl::fx::Cloud::drawSunOcc which uses texture readback
710
;0x0340425C = cmpwi r1, 0
811

src/hooking/camera.cpp

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,6 @@ void CemuHooks::hook_UpdateCameraForGameplay(PPCInterpreter_t* hCPU) {
181181
}
182182

183183

184-
if (auto eventSettings = GetFirstPersonSettingsForActiveEvent()) {
185-
if (eventSettings->ignoreCameraRotation) {
186-
glm::fquat playerRot = mtx.getRotLE();
187-
auto [swing, baseYaw] = swingTwistY(playerRot);
188-
s_wsCameraRotation = baseYaw * glm::angleAxis(glm::radians(180.0f), glm::fvec3(0.0f, 1.0f, 0.0f));
189-
}
190-
}
191-
192184
if (s_isLadderClimbing > 0) {
193185
s_isLadderClimbing--;
194186
}
@@ -320,15 +312,6 @@ void CemuHooks::hook_GetRenderCamera(PPCInterpreter_t* hCPU) {
320312
}
321313

322314
basePos = playerPos;
323-
if (auto eventSettings = GetFirstPersonSettingsForActiveEvent()) {
324-
325-
if (eventSettings->ignoreCameraRotation) {
326-
glm::fquat playerRot = playerMtx.getRotLE();
327-
auto [swing, yaw] = swingTwistY(playerRot);
328-
baseYaw = yaw * glm::angleAxis(glm::radians(180.0f), glm::fvec3(0.0f, 1.0f, 0.0f));
329-
baseYawWithoutClimbingFix = yaw * glm::angleAxis(glm::radians(180.0f), glm::fvec3(0.0f, 1.0f, 0.0f));
330-
}
331-
}
332315
}
333316

334317
s_lastCameraMtx = glm::fmat4x3(glm::translate(glm::identity<glm::fmat4>(), basePos) * glm::mat4(baseYawWithoutClimbingFix));
@@ -556,15 +539,6 @@ void CemuHooks::hook_ModifyProjectionUsingCamera(PPCInterpreter_t* hCPU) {
556539
// take link's direction, then rotate the headset position
557540
BEMatrix34 playerMtx = {};
558541
readMemory(s_playerMtxAddress, &playerMtx);
559-
560-
if (auto eventSettings = GetFirstPersonSettingsForActiveEvent()) {
561-
562-
if (eventSettings->ignoreCameraRotation) {
563-
glm::fquat playerRot = playerMtx.getRotLE();
564-
auto [swing, yaw] = swingTwistY(playerRot);
565-
baseYaw = yaw * glm::angleAxis(glm::radians(180.0f), glm::fvec3(0.0f, 1.0f, 0.0f));
566-
}
567-
}
568542
}
569543

570544
// vr camera
@@ -667,13 +641,6 @@ std::pair<glm::vec3, glm::fquat> CemuHooks::CalculateVRWorldPose(const BESeadLoo
667641
}
668642

669643
basePos = playerPos;
670-
if (auto eventSettings = GetFirstPersonSettingsForActiveEvent()) {
671-
if (eventSettings->ignoreCameraRotation) {
672-
glm::fquat playerRot = playerMtx.getRotLE();
673-
auto [swing, yaw] = swingTwistY(playerRot);
674-
baseYaw = yaw * glm::angleAxis(glm::radians(180.0f), glm::fvec3(0.0f, 1.0f, 0.0f));
675-
}
676-
}
677644
}
678645

679646
// vr camera
@@ -943,6 +910,23 @@ void CemuHooks::hook_GetEventName(PPCInterpreter_t* hCPU) {
943910
}
944911
}
945912

913+
void CemuHooks::hook_ShouldSkipEventCamera(PPCInterpreter_t* hCPU) {
914+
hCPU->instructionPointer = hCPU->sprNew.LR;
915+
916+
if (IsFirstPerson()) {
917+
// disable camera rotation for first-person events, according to the event settings
918+
if (auto eventSettings = GetFirstPersonSettingsForActiveEvent()) {
919+
if (eventSettings->ignoreCameraRotation) {
920+
hCPU->gpr[3] = 1;
921+
return;
922+
}
923+
}
924+
}
925+
926+
// return 0 to just follow regular camera rotation
927+
hCPU->gpr[3] = 0;
928+
}
929+
946930
struct CameraParamValueOffset {
947931
std::string name;
948932
uint32_t offsetInsideCamera;
@@ -996,6 +980,8 @@ void CemuHooks::hook_ReplaceCameraMode(PPCInterpreter_t* hCPU) {
996980
constexpr uint32_t kCameraAiming2Vtbl = 0X101B2EB4;
997981
constexpr uint32_t kCameraMagneCatchVtbl = 0x101BAB4C;
998982

983+
//hCPU->gpr[3] = cameraChaseInstance;
984+
999985
if (hCPU->gpr[5] == kCameraMagneCatchVtbl) {
1000986
if (IsFirstPerson()) {
1001987
//hCPU->gpr[3] = cameraChaseMode;

src/hooking/cemu_hooks.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class CemuHooks {
4848
osLib_registerHLEFunction("coreinit", "hook_UseCameraDistance", &hook_UseCameraDistance);
4949
osLib_registerHLEFunction("coreinit", "hook_ReplaceCameraMode", &hook_ReplaceCameraMode);
5050
osLib_registerHLEFunction("coreinit", "hook_GetEventName", &hook_GetEventName);
51+
osLib_registerHLEFunction("coreinit", "hook_ShouldSkipEventCamera", &hook_ShouldSkipEventCamera);
5152
osLib_registerHLEFunction("coreinit", "hook_OverwriteCameraParam", &hook_OverwriteCameraParam);
5253
osLib_registerHLEFunction("coreinit", "hook_PlayerLadderFix", &hook_PlayerLadderFix);
5354
osLib_registerHLEFunction("coreinit", "hook_PlayerIsRiding", &hook_PlayerIsRiding);
@@ -253,6 +254,7 @@ class CemuHooks {
253254
static void hook_UseCameraDistance(PPCInterpreter_t* hCPU);
254255
static void hook_ReplaceCameraMode(PPCInterpreter_t* hCPU);
255256
static void hook_GetEventName(PPCInterpreter_t* hCPU);
257+
static void hook_ShouldSkipEventCamera(PPCInterpreter_t* hCPU);
256258
static void hook_OverwriteCameraParam(PPCInterpreter_t* hCPU);
257259
static void hook_PlayerLadderFix(PPCInterpreter_t* hCPU);
258260
static void hook_VisualizeRayCastHits(PPCInterpreter_t* hCPU);

0 commit comments

Comments
 (0)