Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions package/Shaders/Common/GBuffer.hlsli
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
#ifndef __GBUFFER_DEPENDENCY_HLSL__
#define __GBUFFER_DEPENDENCY_HLSL__

// https://knarkowicz.wordpress.com/2014/04/16/octahedron-normal-vector-encoding/

namespace GBuffer
{

float2 OctWrap(float2 v)
{
return (1.0 - abs(v.yx)) * (v.xy >= 0.0 ? 1.0 : -1.0);
}

float2 EncodeNormal(float3 n)
{
n.z = max(0.001, sqrt(8.0 - 8.0 * n.z));
n.xy /= n.z;
return n.xy + 0.5;
n = -n;
n /= (abs(n.x) + abs(n.y) + abs(n.z));
n.xy = n.z >= 0.0 ? n.xy : OctWrap(n.xy);
n.xy = n.xy * 0.5 + 0.5;
return n.xy;
}

float3 DecodeNormal(float2 enc)
float3 DecodeNormal(float2 f)
{
float2 fenc = enc * 4.0 - 2.0;
float f = dot(fenc, fenc);
float3 n;
n.xy = fenc * sqrt(1.0 - f / 4.0);
n.z = f / 2.0 - 1.0;
return n;
f = f * 2.0 - 1.0;
// https://twitter.com/Stubbesaurus/status/937994790553227264
float3 n = float3(f.x, f.y, 1.0 - abs(f.x) - abs(f.y));
float t = saturate(-n.z);
n.xy += n.xy >= 0.0 ? -t : t;
return -normalize(n);
}

float2 EncodeNormalVanilla(float3 n)
{
n.z = max(1.0 / 1000.0, sqrt(8.0 + -8.0 * n.z));
n.xy /= n.z;
return n.xy + 0.5;
}

}
Expand Down
12 changes: 4 additions & 8 deletions package/Shaders/DeferredCompositePS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ struct PS_INPUT
struct PS_OUTPUT
{
float4 Main: SV_Target0;
float4 NormalRoughness: SV_Target1;
float4 Normal: SV_Target1;
};

PS_OUTPUT main(PS_INPUT input)
Expand All @@ -115,9 +115,10 @@ PS_OUTPUT main(PS_INPUT input)
float3 specularColor = SpecularTexture[pixCoord];
float3 linDiffuseColor = Color::IrradianceToLinear(diffuseColor);

#if defined(SSGI) || defined(DYNAMIC_CUBEMAPS)
float3 normalGlossiness = NormalRoughnessTexture[pixCoord].xyz;
float3 normalVS = GBuffer::DecodeNormal(normalGlossiness.xy);

#if defined(SSGI) || defined(DYNAMIC_CUBEMAPS)
float3 normalWS = normalize(mul(FrameBuffer::CameraViewInverse[eyeIndex], float4(normalVS, 0)).xyz);

float depth = DepthTexture[pixCoord];
Expand Down Expand Up @@ -311,11 +312,6 @@ PS_OUTPUT main(PS_INPUT input)

#if defined(DEBUG)

# if !defined(SSGI) && !defined(DYNAMIC_CUBEMAPS)
float3 normalGlossiness = NormalRoughnessTexture[pixCoord];
float3 normalVS = GBuffer::DecodeNormal(normalGlossiness.xy);
# endif

# if !defined(SSGI)
float3 albedo = AlbedoTexture[pixCoord];
# endif
Expand All @@ -342,6 +338,6 @@ PS_OUTPUT main(PS_INPUT input)

PS_OUTPUT output;
output.Main = float4(color, 1.0);
output.NormalRoughness = 0;
output.Normal = float4(GBuffer::EncodeNormalVanilla(normalVS), 0.0, 0.0);
return output;
}
2 changes: 1 addition & 1 deletion src/Deferred.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ void Deferred::SetupResources()
D3D11_BLEND_DESC blendDesc{};
blendDesc.IndependentBlendEnable = TRUE;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blendDesc.RenderTarget[1].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_BLUE;
blendDesc.RenderTarget[1].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
DX::ThrowIfFailed(device->CreateBlendState(&blendDesc, compositeBlendState.put()));
Util::SetResourceName(compositeBlendState.get(), "Deferred::CompositeBlendState");

Expand Down
25 changes: 24 additions & 1 deletion src/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,28 @@ namespace Hooks
static inline REL::Relocation<decltype(thunk)> func;
};

struct CreateRenderTarget_Normals
{
static void thunk(RE::BSGraphics::Renderer* This, RE::RENDER_TARGETS::RENDER_TARGET a_target, RE::BSGraphics::RenderTargetProperties* a_properties)
{
RE::BSGraphics::RenderTargetProperties properties = *a_properties;
properties.format.set(RE::BSGraphics::Format::kR10G10B10A2_UNORM);
func(This, a_target, &properties);
}
Comment on lines 601 to +606
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Preserve the shared render-target mutation for the normals targets.

These two hooks now override the format and call func(...) directly, but unlike CreateRenderTarget_Main they never pass the copied properties through globals::state->ModifyRenderTarget(...). That drops the common render-target adjustments from src/State.cpp for both normal buffers, so they no longer inherit flags like UAV support. Please apply the global mutation to the copied struct before calling the original function.

Suggested fix
 struct CreateRenderTarget_Normals
 {
 	static void thunk(RE::BSGraphics::Renderer* This, RE::RENDER_TARGETS::RENDER_TARGET a_target, RE::BSGraphics::RenderTargetProperties* a_properties)
 	{
 		RE::BSGraphics::RenderTargetProperties properties = *a_properties;
 		properties.format.set(RE::BSGraphics::Format::kR10G10B10A2_UNORM);
+		globals::state->ModifyRenderTarget(a_target, &properties);
 		func(This, a_target, &properties);
 	}
 	static inline REL::Relocation<decltype(thunk)> func;
 };
 
 struct CreateRenderTarget_NormalsSwap
 {
 	static void thunk(RE::BSGraphics::Renderer* This, RE::RENDER_TARGETS::RENDER_TARGET a_target, RE::BSGraphics::RenderTargetProperties* a_properties)
 	{
 		RE::BSGraphics::RenderTargetProperties properties = *a_properties;
 		properties.format.set(RE::BSGraphics::Format::kR10G10B10A2_UNORM);
+		globals::state->ModifyRenderTarget(a_target, &properties);
 		func(This, a_target, &properties);
 	}
 	static inline REL::Relocation<decltype(thunk)> func;
 };

Also applies to: 602-606, 967-968

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Hooks.cpp` around lines 591 - 596, The thunk copies a_properties into a
local properties, mutates properties.format, then calls func(...) but fails to
run the shared mutation in globals::state->ModifyRenderTarget, so normals
targets lose common flags (e.g., UAV). Fix: after setting properties.format and
before calling func(This, a_target, &properties), call
globals::state->ModifyRenderTarget(a_target, properties) (or the correct
overload that mutates the struct in-place) and then pass the resulting/modified
properties pointer to func; apply the same change to the other similar thunk
implementations that set the normal buffer formats (the other thunk blocks that
set kR10G10B10A2_UNORM and the other normal-format thunk around the other
reported ranges).

static inline REL::Relocation<decltype(thunk)> func;
};

struct CreateRenderTarget_NormalsSwap
{
static void thunk(RE::BSGraphics::Renderer* This, RE::RENDER_TARGETS::RENDER_TARGET a_target, RE::BSGraphics::RenderTargetProperties* a_properties)
{
RE::BSGraphics::RenderTargetProperties properties = *a_properties;
properties.format.set(RE::BSGraphics::Format::kR10G10B10A2_UNORM);
func(This, a_target, &properties);
}
static inline REL::Relocation<decltype(thunk)> func;
};

struct CreateRenderTarget_RefractionNormals
{
static void thunk(RE::BSGraphics::Renderer* This, RE::RENDER_TARGETS::RENDER_TARGET a_target, RE::BSGraphics::RenderTargetProperties* a_properties)
Expand Down Expand Up @@ -953,7 +975,8 @@ namespace Hooks
logger::info("Hooking BSShaderRenderTargets::Create::CreateRenderTarget(s)");
stl::write_thunk_call<CreateRenderTarget_Main>(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x3F0, 0x3F3, 0x548));
stl::write_thunk_call<CreateRenderTarget_MotionVectors>(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x4F0, 0x4EF, 0x64E));

stl::write_thunk_call<CreateRenderTarget_Normals>(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x458, 0x45B, 0x5B0));
stl::write_thunk_call<CreateRenderTarget_NormalsSwap>(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x46B, 0x46E, 0x5C3));
stl::write_thunk_call<CreateRenderTarget_RefractionNormals>(REL::RelocationID(100458, 107175).address() + REL::Relocate(0x503, 0x502, 0x661));
stl::write_thunk_call<CreateRenderTarget_UnderwaterMask>(REL::RelocationID(100458, 107175).address() + REL::Relocate(0xB19, 0xB19, 0xE06));

Expand Down
Loading