Skip to content

Commit fd04305

Browse files
committed
Set camera projection for world-space debug visualizer
This change got lost somewhere but its quite important
1 parent 288621f commit fd04305

File tree

2 files changed

+71
-63
lines changed

2 files changed

+71
-63
lines changed

src/hooking/camera.cpp

Lines changed: 71 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
#include "utils/debug_draw.h"
21
#include "cemu_hooks.h"
32
#include "instance.h"
43
#include "rendering/openxr.h"
4+
#include "utils/debug_draw.h"
55

66
bool CemuHooks::UseMonoFrameBufferTemporarilyDuringMenusOrPictures() {
77
return IsScreenOpen(ScreenId::PauseMenuInfo_00) || VRManager::instance().XR->GetRenderer()->IsGameCapturing3DFrameBuffer();
@@ -27,6 +27,51 @@ static std::pair<glm::quat, glm::quat> swingTwistY(const glm::quat& q) {
2727
return { swing, twist };
2828
}
2929

30+
// https://github.com/KhronosGroup/OpenXR-SDK/blob/858912260ca616f4c23f7fb61c89228c353eb124/src/common/xr_linear.h#L564C1-L632C2
31+
// https://github.com/aboood40091/sead/blob/45b629fb032d88b828600a1b787729f2d398f19d/engine/library/modules/src/gfx/seadProjection.cpp#L166
32+
33+
static data_VRProjectionMatrixOut calculateFOVAndOffset(XrFovf viewFOV) {
34+
float totalHorizontalFov = viewFOV.angleRight - viewFOV.angleLeft;
35+
float totalVerticalFov = viewFOV.angleUp - viewFOV.angleDown;
36+
37+
float aspectRatio = totalHorizontalFov / totalVerticalFov;
38+
float fovY = totalVerticalFov;
39+
float projectionCenter_offsetX = (viewFOV.angleRight + viewFOV.angleLeft) / 2.0f;
40+
float projectionCenter_offsetY = (viewFOV.angleUp + viewFOV.angleDown) / 2.0f;
41+
42+
data_VRProjectionMatrixOut ret = {};
43+
ret.aspectRatio = aspectRatio;
44+
ret.fovY = fovY;
45+
ret.offsetX = projectionCenter_offsetX;
46+
ret.offsetY = projectionCenter_offsetY;
47+
48+
return ret;
49+
}
50+
51+
static glm::mat4 calculateProjectionMatrix(float nearZ, float farZ, const XrFovf& fov) {
52+
float l = tanf(fov.angleLeft) * nearZ;
53+
float r = tanf(fov.angleRight) * nearZ;
54+
float b = tanf(fov.angleDown) * nearZ;
55+
float t = tanf(fov.angleUp) * nearZ;
56+
57+
float invW = 1.0f / (r - l);
58+
float invH = 1.0f / (t - b);
59+
float invD = 1.0f / (farZ - nearZ);
60+
61+
glm::mat4 dst = {};
62+
dst[0][0] = 2.0f * nearZ * invW;
63+
dst[1][1] = 2.0f * nearZ * invH;
64+
dst[0][2] = (r + l) * invW;
65+
dst[1][2] = (t + b) * invH;
66+
dst[2][2] = -(farZ + nearZ) * invD;
67+
dst[2][3] = -(2.0f * farZ * nearZ) * invD;
68+
dst[3][2] = -1.0f;
69+
dst[3][3] = 0.0f;
70+
71+
return dst;
72+
}
73+
74+
3075
float hardcodedSwimOffset = 0.0f;
3176
float hardcodedRidingOffset = 0.65f;
3277
float hardcodedCrouchOffset = 0.3f;
@@ -88,7 +133,7 @@ void CemuHooks::hook_UpdateCameraForGameplay(PPCInterpreter_t* hCPU) {
88133

89134
PlayerMoveBitFlags moveBits = actor.moveBitFlags.getLE();
90135
s_isSwimming = HAS_FLAG(moveBits, PlayerMoveBitFlags::IS_SWIMMING_OR_CLIMBING | PlayerMoveBitFlags::IS_SWIMMING);
91-
s_isCrouching = HAS_FLAG(moveBits, PlayerMoveBitFlags::IS_CROUCHING);
136+
s_isCrouching = HAS_FLAG(moveBits, PlayerMoveBitFlags::IS_CROUCHING);
92137

93138
// Todo: move those and their hooks in controls.cpp ?
94139
auto gameState = VRManager::instance().XR->m_gameState.load();
@@ -100,23 +145,19 @@ void CemuHooks::hook_UpdateCameraForGameplay(PPCInterpreter_t* hCPU) {
100145

101146
auto now = std::chrono::steady_clock::now();
102147
std::chrono::milliseconds crouchLerpDuration{ 150 };
103-
if (s_isCrouching != s_wasCrouching)
104-
{
148+
if (s_isCrouching != s_wasCrouching) {
105149
crouch_state_change_time = now;
106150
}
107151
auto test = 0.8f;
108-
if (now <= crouch_state_change_time + crouchLerpDuration)
109-
{
152+
if (now <= crouch_state_change_time + crouchLerpDuration) {
110153
auto elapsed = std::chrono::duration<float>(now - crouch_state_change_time);
111154
auto duration = std::chrono::duration<float>(crouchLerpDuration);
112155
float t = elapsed.count() / duration.count();
113156
t = glm::clamp(t, 0.0f, 1.0f);
114-
if (s_isCrouching)
115-
{
157+
if (s_isCrouching) {
116158
actualCrouchOffset = glm::mix(0.0f, test, t);
117159
}
118-
else
119-
{
160+
else {
120161
actualCrouchOffset = glm::mix(test, 0.0f, t);
121162
}
122163
}
@@ -267,7 +308,7 @@ void CemuHooks::hook_GetRenderCamera(PPCInterpreter_t* hCPU) {
267308
BEMatrix34 playerMtx = {};
268309
readMemory(s_playerMtxAddress, &playerMtx);
269310
glm::fvec3 playerPos = playerMtx.getPos().getLE();
270-
311+
271312
if (s_isRiding) {
272313
playerPos.y -= hardcodedRidingOffset;
273314
}
@@ -305,6 +346,20 @@ void CemuHooks::hook_GetRenderCamera(PPCInterpreter_t* hCPU) {
305346
glm::mat4 newWorldVR = glm::translate(glm::mat4(1.0f), newPos) * glm::mat4_cast(newRot);
306347
glm::mat4 newViewVR = glm::inverse(newWorldVR);
307348

349+
if (side == EyeSide::RIGHT && GetSettings().ShowDebugOverlay()) {
350+
glm::mat4 proj = calculateProjectionMatrix(GetSettings().GetZNear(), GetSettings().GetZFar(), VRManager::instance().XR->GetRenderer()->GetFOV(side).value());
351+
352+
// transpose the sead-convention (row-major) projections to standard column-major
353+
glm::mat4 vrProj = glm::transpose(proj);
354+
355+
glm::mat4 vrVP = vrProj * newViewVR;
356+
//DebugDraw::instance().Frustum(vrVP, IM_COL32(0, 255, 0, 255));
357+
358+
// store the right-eye projection matrix to transform the debug lines with
359+
// use right-side due to that being the one shown in the 2D view
360+
DebugDraw::instance().SetViewProjection(vrVP);
361+
}
362+
308363
camera.mtx.setLEMatrix(newViewVR);
309364

310365
camera.pos = newPos;
@@ -328,51 +383,6 @@ void CemuHooks::hook_GetRenderCamera(PPCInterpreter_t* hCPU) {
328383
constexpr uint32_t seadOrthoProjection = 0x1027B5BC;
329384
constexpr uint32_t seadPerspectiveProjection = 0x1027B54C;
330385

331-
332-
// https://github.com/KhronosGroup/OpenXR-SDK/blob/858912260ca616f4c23f7fb61c89228c353eb124/src/common/xr_linear.h#L564C1-L632C2
333-
// https://github.com/aboood40091/sead/blob/45b629fb032d88b828600a1b787729f2d398f19d/engine/library/modules/src/gfx/seadProjection.cpp#L166
334-
335-
static data_VRProjectionMatrixOut calculateFOVAndOffset(XrFovf viewFOV) {
336-
float totalHorizontalFov = viewFOV.angleRight - viewFOV.angleLeft;
337-
float totalVerticalFov = viewFOV.angleUp - viewFOV.angleDown;
338-
339-
float aspectRatio = totalHorizontalFov / totalVerticalFov;
340-
float fovY = totalVerticalFov;
341-
float projectionCenter_offsetX = (viewFOV.angleRight + viewFOV.angleLeft) / 2.0f;
342-
float projectionCenter_offsetY = (viewFOV.angleUp + viewFOV.angleDown) / 2.0f;
343-
344-
data_VRProjectionMatrixOut ret = {};
345-
ret.aspectRatio = aspectRatio;
346-
ret.fovY = fovY;
347-
ret.offsetX = projectionCenter_offsetX;
348-
ret.offsetY = projectionCenter_offsetY;
349-
350-
return ret;
351-
}
352-
353-
static glm::mat4 calculateProjectionMatrix(float nearZ, float farZ, const XrFovf& fov) {
354-
float l = tanf(fov.angleLeft) * nearZ;
355-
float r = tanf(fov.angleRight) * nearZ;
356-
float b = tanf(fov.angleDown) * nearZ;
357-
float t = tanf(fov.angleUp) * nearZ;
358-
359-
float invW = 1.0f / (r - l);
360-
float invH = 1.0f / (t - b);
361-
float invD = 1.0f / (farZ - nearZ);
362-
363-
glm::mat4 dst = {};
364-
dst[0][0] = 2.0f * nearZ * invW;
365-
dst[1][1] = 2.0f * nearZ * invH;
366-
dst[0][2] = (r + l) * invW;
367-
dst[1][2] = (t + b) * invH;
368-
dst[2][2] = -(farZ + nearZ) * invD;
369-
dst[2][3] = -(2.0f * farZ * nearZ) * invD;
370-
dst[3][2] = -1.0f;
371-
dst[3][3] = 0.0f;
372-
373-
return dst;
374-
}
375-
376386
void CemuHooks::hook_GetRenderProjection(PPCInterpreter_t* hCPU) {
377387
hCPU->instructionPointer = hCPU->sprNew.LR;
378388

@@ -742,7 +752,6 @@ void CemuHooks::hook_CheckIfCameraCanSeePos(PPCInterpreter_t* hCPU) {
742752
}
743753

744754

745-
746755
void CemuHooks::hook_ModifyPixelUniformBlockData(PPCInterpreter_t* hCPU) {
747756
hCPU->instructionPointer = hCPU->sprNew.LR;
748757

@@ -753,12 +762,12 @@ void CemuHooks::hook_ModifyPixelUniformBlockData(PPCInterpreter_t* hCPU) {
753762

754763
glm::fvec4 ubData = {};
755764
readMemory(hCPU->gpr[5], &ubData);
756-
765+
757766
XrFovf currFOV = currFovOpt.value();
758767
auto newProjection = calculateFOVAndOffset(currFOV);
759768

760-
ubData.x = 0.5f+newProjection.offsetX.getLE();
761-
ubData.y = 0.5f+newProjection.offsetY.getLE();
769+
ubData.x = 0.5f + newProjection.offsetX.getLE();
770+
ubData.y = 0.5f + newProjection.offsetY.getLE();
762771

763772
writeMemory(hCPU->gpr[5], &ubData);
764773
}
@@ -1035,7 +1044,7 @@ void CemuHooks::hook_OverwriteCameraParam(PPCInterpreter_t* hCPU) {
10351044
auto& paramList = storedCameraParameters[actionPtr];
10361045
// store parameter offset if not already stored
10371046
auto it = std::find_if(paramList.begin(), paramList.end(), [&paramNameStr](const CameraParamValueOffset& entry) {
1038-
return entry.name == paramNameStr;
1047+
return entry.name == paramNameStr;
10391048
});
10401049
if (it == paramList.end()) {
10411050
// get offset by calling original function first
@@ -1098,7 +1107,7 @@ void CemuHooks::hook_PlayerLadderFix(PPCInterpreter_t* hCPU) {
10981107
void CemuHooks::hook_VisualizeRayCastHits(PPCInterpreter_t* hCPU) {
10991108
hCPU->instructionPointer = hCPU->sprNew.LR;
11001109

1101-
if (VRManager::instance().XR->GetRenderer() == nullptr) {
1110+
if (VRManager::instance().XR->GetRenderer() == nullptr || !GetSettings().ShowDebugOverlay()) {
11021111
return;
11031112
}
11041113

src/utils/debug_draw.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ class DebugDraw {
2020
void Frustum(const glm::mat4& viewProjection, uint32_t color = IM_COL32(255, 255, 0, 255), float thickness = 1.0f);
2121

2222
// -- VP matrix for rendering (set from camera hooks) --
23-
2423
// Stores the view-projection matrix used for rendering debug primitives.
2524
// Must be a standard column-major VP matrix in game world space.
2625
// Call from the camera hook each frame.

0 commit comments

Comments
 (0)