Allow for grabbing camera data from Unreal Engine

Relies on https://github.com/FakeMichau/UeLowLatency and UE4SS

Now the requirement for UE games is lowered to just an upscaler + Reflex + Hudless (can be from Hudfix). But seems like the FOV reported by DRG is slightly wrong, will need to check.
This commit is contained in:
FakeMichau committed 2026-09-25 20:32:18 +02:00
1 parent 4bb852642a
commit 2accb06608
5 files changed
+98 -9

No files matched your search

@@ -2,6 +2,7 @@
#include "Reprojection_Dx12.h"
#include <hudfix/Hudfix_Dx12.h>
#include <hudfix/Hudfix_Dx11.h>
#include <menu/menu_overlay_dx.h>
#include <magic_enum.hpp>
@@ -185,6 +186,23 @@ void Reprojection_Dx12::EvaluateState(ID3D12Device* device, FG_Constants& fgCons
{
Deactivate();
}
if (State::Instance().fgChanged)
{
LOG_DEBUG("FGchanged");
State::Instance().fgChanged = false;
Hudfix_Dx12::ResetCounters();
Hudfix_Dx11::ResetCounters();
// Pause for 10 frames
UpdateTarget();
// Release FG mutex
if (Mutex.getOwner() == 2)
Mutex.unlockThis(2);
}
}
std::optional<double> Reprojection_Dx12::ReadGpuTime(void* commandQueue)
+16 -8
View File
@@ -582,16 +582,24 @@ HMODULE LibraryLoadHooks::LoadLibraryCheckW(std::wstring libName, LPCWSTR lpLibF
auto module = NtdllProxy::LoadLibraryExW_Ldr(libName.c_str(), NULL, NULL);
auto setTickStartCallback =
(PFN_setTickCallback) KernelBaseProxy::GetProcAddress_()(module, "setTickStartCallback");
auto setTickEndCallback =
(PFN_setTickCallback) KernelBaseProxy::GetProcAddress_()(module, "setTickEndCallback");
if (module)
{
auto setTickStartCallback =
(PFN_setTickCallback) KernelBaseProxy::GetProcAddress_()(module, "setTickStartCallback");
auto setTickEndCallback =
(PFN_setTickCallback) KernelBaseProxy::GetProcAddress_()(module, "setTickEndCallback");
auto setCameraUpdateCallback =
(PFN_setCameraUpdateExternal) KernelBaseProxy::GetProcAddress_()(module, "setCameraUpdateCallback");
if (setTickStartCallback)
setTickStartCallback(InputUeLowLatency::tickStart);
if (setTickStartCallback)
setTickStartCallback(InputUeLowLatency::tickStart);
if (setTickEndCallback)
setTickEndCallback(InputUeLowLatency::tickEnd);
if (setTickEndCallback)
setTickEndCallback(InputUeLowLatency::tickEnd);
if (setCameraUpdateCallback)
setCameraUpdateCallback(InputUeLowLatency::cameraUpdate);
}
return module;
}
@@ -1,6 +1,10 @@
#include "pch.h"
#include "input_uell.h"
#include <DirectXMath.h>
using namespace DirectX;
void InputUeLowLatency::init()
{
if (inited)
@@ -79,3 +83,56 @@ void InputUeLowLatency::tickEnd(int64_t frameId, float DeltaSeconds, bool bIdleM
return;
}
}
static void GetCameraBasis(const float cameraRotation[3], float cameraUp[3], float cameraRight[3],
float cameraForward[3])
{
float pitch = DirectX::XMConvertToRadians(cameraRotation[0]);
float yaw = DirectX::XMConvertToRadians(cameraRotation[1]);
float roll = DirectX::XMConvertToRadians(cameraRotation[2]);
float SP, CP, SY, CY, SR, CR;
DirectX::XMScalarSinCos(&SP, &CP, pitch);
DirectX::XMScalarSinCos(&SY, &CY, yaw);
DirectX::XMScalarSinCos(&SR, &CR, roll);
cameraForward[0] = CP * CY;
cameraForward[1] = CP * SY;
cameraForward[2] = SP;
cameraRight[0] = SR * SP * CY - CR * SY;
cameraRight[1] = SR * SP * SY + CR * CY;
cameraRight[2] = -SR * CP;
cameraUp[0] = -(CR * SP * CY + SR * SY);
cameraUp[1] = CY * SR - CR * SP * SY;
cameraUp[2] = CR * CP;
}
void InputUeLowLatency::cameraUpdate(int64_t frameId, float cameraPosition[3], float cameraRotation[3], float fovAngle)
{
// Technically FSRFG input might have the camera data but not guaranteed
// if (State::Instance().activeFgInput == FGInput::DLSSG)
// return;
if (auto fg = State::Instance().currentFG)
{
auto index = frameId % BUFFER_COUNT;
float cameraUp[3];
float cameraRight[3];
float cameraForward[3];
GetCameraBasis(cameraRotation, cameraUp, cameraRight, cameraForward);
fg->SetCameraData(cameraPosition, cameraUp, cameraRight, cameraForward, index);
UINT64 width = 0;
UINT height = 0;
fg->GetInterpolationRect(width, height, index);
float aspectRatio = (float) width / (float) height;
// TODO: camera near and far are placeholders
fg->SetCameraValues(0.01f, 10000.f, DirectX::XMConvertToRadians(fovAngle), aspectRatio, 0.0f, index);
}
}
@@ -3,7 +3,11 @@
#include "input_common.h"
typedef void (*PFN_FLTickExternal)(int64_t frameId, float DeltaSeconds, bool bIdleMode);
typedef void (*PFN_CameraUpdateExternal)(int64_t frameId, float cameraPosition[3],
float cameraRotation[3], // Pitch, Yaw, Roll
float fovAngle);
typedef void (*PFN_setTickCallback)(PFN_FLTickExternal callback);
typedef void (*PFN_setCameraUpdateExternal)(PFN_CameraUpdateExternal callback);
class InputUeLowLatency
{
@@ -19,4 +23,5 @@ class InputUeLowLatency
static void init();
static void tickEnd(int64_t frameId, float DeltaSeconds, bool bIdleMode);
static void tickStart(int64_t frameId, float DeltaSeconds, bool bIdleMode);
static void cameraUpdate(int64_t frameId, float cameraPosition[3], float cameraRotation[3], float fovAngle);
};
+2 -1
View File
@@ -4338,7 +4338,8 @@ void MenuCommon::RenderFrameGenerationRuntimeSettings(RenderMenuContext& ctx)
if (currentFeature != nullptr && !currentFeature->IsFrozen() &&
((state.activeFgOutput == FGOutput::FSRFG && FfxApiProxy::IsFGReady()) ||
(state.activeFgOutput == FGOutput::XeFG && XeFGProxy::Module() != nullptr) ||
(state.activeFgOutput == FGOutput::DLSSG && StreamlineProxy::Module() != nullptr)))
(state.activeFgOutput == FGOutput::DLSSG && StreamlineProxy::Module() != nullptr) ||
state.activeFgOutput == FGOutput::Reprojection))
{
const bool dx11HudfixTracking = state.swapchainInteropApi == SwapchainInteropApi::Dx11wDx12;
const bool hudfixTrackingSupported =