From 6374a4b274e5048c56a820402275e28cf5ac1d39 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Mon, 29 Jun 2026 11:15:01 -0400 Subject: Cleanup and test some lighting stuff Signed-off-by: Andrew Opalach --- LUT.cs | 35 ++++- Plugin.cs | 243 ++++++++++++++++++++------------- Shaders/Original/alpha_as_luma.dxbc.xz | Bin 0 -> 596 bytes Shaders/alpha_as_luma.hlsl | 58 ++++++++ 4 files changed, 241 insertions(+), 95 deletions(-) create mode 100644 Shaders/Original/alpha_as_luma.dxbc.xz create mode 100644 Shaders/alpha_as_luma.hlsl diff --git a/LUT.cs b/LUT.cs index cb8975c..1181216 100644 --- a/LUT.cs +++ b/LUT.cs @@ -3,6 +3,7 @@ using System.Text; using System.Numerics; using SharpPluginLoader.Core; +using SharpPluginLoader.Core.Memory; using SharpPluginLoader.Core.Rendering; namespace WorldTuningTool @@ -13,13 +14,41 @@ namespace WorldTuningTool public WorldLUT() { } + private string[] lutList = []; + public string[] GetLUTs() { - if (!Directory.Exists(lutsPath)) + return lutList; + } + + public void ReloadLUTs() + { + if (Directory.Exists(lutsPath)) { - return []; + lutList = Directory.GetFiles(lutsPath); + } + } + + public static nint ProbeD3DResource(nint lightingObject) + { + nint lutTexture = MemoryUtil.Read(lightingObject + 0x1C0); + nint d3dResource = 0x0; + if (lutTexture != 0x0) + { + if (Renderer.IsDirectX12) + { + d3dResource = MemoryUtil.Read(lutTexture + 0x10); + } + else + { + d3dResource = MemoryUtil.Read(lutTexture + 0x60); + if (d3dResource != 0x0) + { + d3dResource = MemoryUtil.Read(d3dResource + 0x18); + } + } } - return Directory.GetFiles(lutsPath); + return d3dResource; } // https://github.com/AsteriskAmpersand/CrappyLUTStudio--CLUTS-/blob/5af10daaa5f295b106cc5db09530a6fe5a4320d4/LUT.py#L35 diff --git a/Plugin.cs b/Plugin.cs index 0058458..e9ecb56 100755 --- a/Plugin.cs +++ b/Plugin.cs @@ -6,22 +6,22 @@ using System.Numerics; using System.Globalization; using System.Runtime.CompilerServices; -#if SHADER_FEATURES using System.Runtime.InteropServices; -#endif #if ENABLE_ASSERTS using System.Diagnostics; #endif using ImGuiNET; using SharpPluginLoader.Core; +using SharpPluginLoader.Core.Configuration; +using SharpPluginLoader.Core.Memory; +using SharpPluginLoader.Core.Entities; +#if SHADER_FEATURES using SharpPluginLoader.Core.Rendering; +#endif #if RESOURCE_ADJUSTMENT using SharpPluginLoader.Core.Resources; #endif -using SharpPluginLoader.Core.Configuration; -using SharpPluginLoader.Core.Memory; -using SharpPluginLoader.Core.Entities; // @TODO: // - Configurable Broad Area Shadow Resolution. @@ -1394,6 +1394,8 @@ namespace WorldTuningTool } private static MtObject? sMhScene = null; + private static MtObject? sMhMain = null; + private static MtObject? sMhRender = null; private static Parameter hqMode = newParameter("HQ Mode", 0xE9A3, ParameterType.BOOL); @@ -1568,10 +1570,6 @@ namespace WorldTuningTool newFrameParameter("Primary Shadow Radius", 0x1EC, ParameterType.FLOAT, pStep(0.0001f)) }; - private static MtObject? sLightProbes = null; - private static Parameter[] lightProbesParameters = { - newParameter("Debug Mode", 0x98, ParameterType.INT, pStep(1)) - }; private delegate nint CreateLightingObject(); private delegate nint DestroyLightingObject(nint lightingObjectInternal, int unknownInt); private Hook? createLightingObject; @@ -1579,12 +1577,14 @@ namespace WorldTuningTool private nint lightingObject = 0x0; private delegate void SetLightingParameters(nint lightingObjectInternal); private Hook? setLightingParams; + private NativeAction setLightingParamsFunc; private delegate void UpdateLightingParameters(nint stackOffset, nint lightingObjectInternal); private Hook? updateLightingParams; private Hook? updateLutBlend; private static WorldLUT lut = new WorldLUT(); private static string selectedLut = ""; - private static bool selectedLutInavlid = false; + private static bool lutSelectionStarted = false; + private static bool selectedLutInvalid = false; private static Parameter[] lightingParameters = { newParameter("Light Tone Map Type", 0x16C, ParameterType.INT, pMinMaxStep(1, 6, 1)), newParameter("Light Compute Luminance", 0x170, ParameterType.BOOL), @@ -1605,6 +1605,14 @@ namespace WorldTuningTool newParameter("Volume Edge Sharpness", 0x198, ParameterType.FLOAT, pStep(0.00001f)), newParameter("Volume Downsample", 0x210, ParameterType.BOOL) }; + private static Parameter[] brightnessParameters = { + newParameter("Gamma Correct", 0x1C8, ParameterType.FLOAT, pStep(0.001f)), + newParameter("Gamma Correct EX", 0x1CC, ParameterType.FLOAT, pStep(0.001f)) + }; + private static MtObject? sLightProbes = null; + private static Parameter[] lightProbesParameters = { + newParameter("Debug Mode", 0x98, ParameterType.INT, pStep(1)) + }; private delegate nint CreateBloomObject(); private delegate nint CreateBloomObject2(nint unknownPtr); @@ -1707,8 +1715,6 @@ namespace WorldTuningTool newParameter("TAA Sharpend Ignore Edges", 0x19C, ParameterType.BOOL) }; - private static MtObject? sMain = null; - private static Parameter[] allParameters = new Parameter[]{ hqMode } .Concat(lodParameters) .Concat(snowParameters) @@ -2120,6 +2126,7 @@ namespace WorldTuningTool createLightingObject = Hook.Create(0x1424CDE20, CreateLightingObjectHook); destroyLightingObject = Hook.Create(0x1424CE380, DestroyLightingObjectHook); // nint, int setLightingParams = Hook.Create(0x1424CF1C0, SetLightingParametersHook); // nint + setLightingParamsFunc = new NativeAction(0x1424CF1C0); updateLutBlend = Hook.Create(0x1416D8DF0, UpdateLutBlendHook); // nint, nint createBloomObject = Hook.Create(0x1424CB3C0, CreateBloomObjectHook); @@ -2426,7 +2433,8 @@ namespace WorldTuningTool public void OnLoad() { - sMain = SingletonManager.GetSingleton("sMhMain")!; + sMhMain = SingletonManager.GetSingleton("sMhMain")!; + sMhRender = SingletonManager.GetSingleton("sMhRender")!; sMhScene = SingletonManager.GetSingleton("sMhScene")!; sLightProbes = SingletonManager.GetSingleton("sLightProbes")!; Config config = getConfig(); @@ -2451,8 +2459,7 @@ namespace WorldTuningTool config.Overrides.Add(area, new List()); } } - List globalOverrides = config.Overrides[globalStage]; - foreach (Override ovG in globalOverrides) + foreach (Override ovG in config.Overrides[globalStage]) { ovG.Set(); } @@ -2495,35 +2502,44 @@ namespace WorldTuningTool { HandleAreaChange(stage); } + hqMode.Update(sMhScene!.Instance); + foreach (Parameter param in lodParameters) { param.Update(sMhScene!.Instance); } + foreach (Parameter param in passthroughParameters) { param.Update(sMhScene!.Instance); } + foreach (Parameter param in shadowCascadeParameters) { param.Update(sMhScene!.Instance); } + foreach (Parameter param in contactShadowParameters) { param.Update(sMhScene!.Instance); } + foreach (Parameter param in snowParameters) { param.Update(sMhScene!.Instance); } + foreach (Parameter param in ssaoParameters) { param.Update(sMhScene!.Instance); } + foreach (Parameter param in sslrParameters) { param.Update(sMhScene!.Instance); } + if (lightingObject != 0x0) { foreach (Parameter param in lightingParameters) @@ -2531,10 +2547,17 @@ namespace WorldTuningTool param.Update(lightingObject); } } + foreach (Parameter param in lightProbesParameters) { param.Update(sLightProbes!.Instance); } + + foreach (Parameter param in brightnessParameters) + { + param.Update(sMhRender!.Instance); + } + if (bloomObject != 0x0) { foreach (Parameter param in bloomParameters) @@ -2542,6 +2565,7 @@ namespace WorldTuningTool param.Update(bloomObject); } } + if (dofObject != 0x0) { foreach (Parameter param in dofParameters) @@ -2552,6 +2576,7 @@ namespace WorldTuningTool } } } + if (motionBlurObject != 0x0) { foreach (Parameter param in motionBlurParameters) @@ -2562,6 +2587,7 @@ namespace WorldTuningTool } } } + if (fxaaObject != 0x0) { foreach (Parameter param in fxaaParameters) @@ -2569,6 +2595,7 @@ namespace WorldTuningTool param.Update(fxaaObject); } } + if (taaObject != 0x0) { foreach (Parameter param in taaParameters) @@ -2863,7 +2890,6 @@ namespace WorldTuningTool setLightingParams!.Original(lightingObjectInternal); if (lightingObject == lightingObjectInternal) { - // LUT texture should be set at this point. selectedLut = ""; } } @@ -3146,14 +3172,9 @@ namespace WorldTuningTool ImGui.EndCombo(); } ImGui.SameLine(); - if (ImGui.Button("Global")) - { - selectedStage = globalStage; - } - ImGui.SameLine(); Config config = getConfig(); - bool invalidStage = !config.Overrides.ContainsKey(currentStage); - if (invalidStage) + bool errorStage = !config.Overrides.ContainsKey(currentStage); + if (errorStage) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); @@ -3162,11 +3183,16 @@ namespace WorldTuningTool { selectedStage = currentStage; } - if (invalidStage) + if (errorStage) { ImGui.PopStyleVar(); ImGui.PopItemFlag(); } + ImGui.SameLine(); + if (ImGui.Button("Global")) + { + selectedStage = globalStage; + } List selectedOverrides = config.Overrides[selectedStage]; if (ImGui.Button("Add override")) @@ -3279,7 +3305,7 @@ namespace WorldTuningTool ImGui.Separator(); - // We now have to consider both global and stage overrides. + // From this point forward, we have to consider both globalOverrides and stageOverrides. globalOverrides = config.Overrides[globalStage]; ImGui.PushID("Set"); @@ -3694,6 +3720,7 @@ namespace WorldTuningTool if (ImGui.CollapsingHeader("Sunlight and Shadows")) { shadowResParameter.Draw(width); + ImGui.Separator(); ImGui.Text($"shadowObject: 0x{shadowAddr:X}, shadowAddr: 0x{shadowObject:X}"); /* if (ImGui.CollapsingHeader("Pass 1")) @@ -3717,6 +3744,7 @@ namespace WorldTuningTool ImGui.PopID(); } */ + ImGui.Separator(); ImGui.Text($"Address: 0x{sMhScene!.Instance:X}"); foreach (Parameter param in shadowCascadeParameters) { @@ -3802,59 +3830,77 @@ namespace WorldTuningTool { if (lightingObject != 0x0) { - nint lutTexture = MemoryUtil.Read(lightingObject + 0x1C0); - nint d3dResource = 0x0; - if (lutTexture != 0x0) + ImGui.Text($"Address: 0x{lightingObject:X}"); + if (ImGui.CollapsingHeader("LUT")) { - if (Renderer.IsDirectX12) + nint d3dResource = WorldLUT.ProbeD3DResource(lightingObject); + if (d3dResource != 0x0) { - d3dResource = MemoryUtil.Read(lutTexture + 0x10); - } - else - { - d3dResource = MemoryUtil.Read(lutTexture + 0x60); - if (d3dResource != 0x0) + if (ImGui.Button("Reset")) { - d3dResource = MemoryUtil.Read(d3dResource + 0x18); + // Attempt to force check for reloading LUT to pass. + MemoryUtil.GetRef(lightingObject + 0x1D4) = MemoryUtil.GetRef(lightingObject + 0x1D0) + 1.0f; } - } - } - if (d3dResource != 0x0) - { - ImGui.SetNextItemWidth(width * 0.65f); - bool prevLutWasInvalid = selectedLutInavlid; - if (prevLutWasInvalid) - { - ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); - } - if (ImGui.BeginCombo("LUT", selectedLut, ImGuiComboFlags.HeightLarge)) - { + ImGui.SameLine(); + ImGui.SetNextItemWidth(width * 0.625f); + bool prevLutWasInvalid = selectedLutInvalid; if (prevLutWasInvalid) { - ImGui.PopStyleColor(); + ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); } - foreach (string lutPath in lut.GetLUTs()) + if (ImGui.BeginCombo("##LUT Files", selectedLut, ImGuiComboFlags.HeightLarge)) { - string lutFile = Path.GetFileName(lutPath); - bool isSelected = selectedLut == lutFile; - if (ImGui.Selectable(lutFile, isSelected)) + if (prevLutWasInvalid) + { + ImGui.PopStyleColor(); + } + if (!lutSelectionStarted) { - selectedLutInavlid = !lut.OverwriteFromFile(d3dResource, lutPath); - selectedLut = lutFile; + lut.ReloadLUTs(); + lutSelectionStarted = true; + } + foreach (string lutPath in lut.GetLUTs()) + { + string lutFile = Path.GetFileName(lutPath); + bool isSelected = selectedLut == lutFile; + if (ImGui.Selectable(lutFile, isSelected)) + { + selectedLutInvalid = !lut.OverwriteFromFile(d3dResource, lutPath); + selectedLut = lutFile; + } } + ImGui.EndCombo(); } - ImGui.EndCombo(); + else + { + if (prevLutWasInvalid) + { + ImGui.PopStyleColor(); + } + lutSelectionStarted = false; + } + } + nint lutMap0 = MemoryUtil.Read(lightingObject + 0x1A8); + if (lutMap0 != 0x0) + { + ImGui.Text($"LUT Map 0: {Marshal.PtrToStringAnsi(lutMap0 + 0xC)!}"); } - else if (prevLutWasInvalid) + nint lutMap1 = MemoryUtil.Read(lightingObject + 0x1B0); + if (lutMap1 != 0x0) { - ImGui.PopStyleColor(); + ImGui.Text($"LUT Map 1: {Marshal.PtrToStringAnsi(lutMap1 + 0xC)!}"); } } - ImGui.Text($"Address: 0x{lightingObject:X}"); foreach (Parameter param in lightingParameters) { param.Draw(width); } + ImGui.Separator(); + } + ImGui.Text($"Address: 0x{sMhRender!.Instance:X}"); + foreach (Parameter param in brightnessParameters) + { + param.Draw(width); } ImGui.Separator(); ImGui.Text($"Address: 0x{sLightProbes!.Instance:X}"); @@ -3947,58 +3993,63 @@ namespace WorldTuningTool ImGui.EndTooltip(); } - if (ImGui.Checkbox("Continous SSLR Temporal Reset", ref continousSSLRTemporalReset)) + if (ImGui.CollapsingHeader("Tests")) { - if (continousSSLRTemporalReset) + if (ImGui.Checkbox("Continous SSLR Temporal Reset", ref continousSSLRTemporalReset)) { - forceSSLRTemporalReset.Enable(); + if (continousSSLRTemporalReset) + { + forceSSLRTemporalReset.Enable(); + } + else + { + forceSSLRTemporalReset.Disable(); + } } - else + if (ImGui.BeginItemTooltip()) { - forceSSLRTemporalReset.Disable(); + ImGui.Text("Don't reference tBlendMap in SSLR resolve."); + ImGui.EndTooltip(); } - } - if (ImGui.BeginItemTooltip()) - { - ImGui.Text("Don't reference tBlendMap in SSLR resolve."); - ImGui.EndTooltip(); - } - if (ImGui.Checkbox("Skip SSLR Mip Mapping", ref skipSSLRMipMapping)) - { - if (skipSSLRMipMapping) + if (ImGui.Checkbox("Skip SSLR Mip Mapping", ref skipSSLRMipMapping)) { - ssrRes4.Enable(); - } - else - { - ssrRes4.Disable(); + if (skipSSLRMipMapping) + { + ssrRes4.Enable(); + } + else + { + ssrRes4.Disable(); + } } - } - if (ImGui.Checkbox("Force unknown _FULL_RES (Probably Useless)", ref unknownFullResPath)) - { - if (unknownFullResPath) + if (ImGui.Checkbox("Force unknown _FULL_RES (Probably Useless)", ref unknownFullResPath)) { - ssrRes3.Enable(); - } - else - { - ssrRes3.Disable(); + if (unknownFullResPath) + { + ssrRes3.Enable(); + } + else + { + ssrRes3.Disable(); + } } + + ImGui.Separator(); } ImGui.PushItemWidth(width * 0.15f); - ImGui.Text($"FPS: {MemoryUtil.GetRef(sMain!.Instance + 0x68)}"); - ImGui.Text($"Delta Time: {MemoryUtil.GetRef(sMain!.Instance + 0x94)}"); + ImGui.Text($"FPS: {MemoryUtil.GetRef(sMhMain!.Instance + 0x68)}"); + ImGui.Text($"Delta Time: {MemoryUtil.GetRef(sMhMain!.Instance + 0x94)}"); // Locations taken from MHW-DTI-Dumps/wip_dump_15_20_00.h. - ImGui.InputFloat("Simulation FPS", ref MemoryUtil.GetRef(sMain!.Instance + 0x58)); + ImGui.InputFloat("Simulation FPS", ref MemoryUtil.GetRef(sMhMain!.Instance + 0x58)); if (ImGui.BeginItemTooltip()) { ImGui.Text("This does not apply to jiggle physics."); ImGui.EndTooltip(); } - ImGui.InputFloat("Max FPS", ref MemoryUtil.GetRef(sMain!.Instance + 0x5C)); + ImGui.InputFloat("Max FPS", ref MemoryUtil.GetRef(sMhMain!.Instance + 0x5C)); ImGui.PopItemWidth(); } } @@ -4031,7 +4082,15 @@ namespace WorldTuningTool public unsafe void OnCreateShader(ShaderInfo *info) { string hash = new string(info->DxbcHash); - if (hash == "9ff245fb-4fd555e0-04d0ef15-84609fe1") + if (hash == "0c3dacbd-32c175d5-10d80d04-cce7e689") + { + if (replaceShaderFromFile(info, $"{shaderPath}/alpha_as_luma.hlsl")) + { + info->Replacement.Type = ShaderSourceType.HLSL; + Log.Info("Alpha as luma shader replaced."); + } + } + else if (hash == "9ff245fb-4fd555e0-04d0ef15-84609fe1") { if (replaceShaderFromFile(info, $"{shaderPath}/fxaa_max_quality.hlsl")) { diff --git a/Shaders/Original/alpha_as_luma.dxbc.xz b/Shaders/Original/alpha_as_luma.dxbc.xz new file mode 100644 index 0000000..3ec9fa8 Binary files /dev/null and b/Shaders/Original/alpha_as_luma.dxbc.xz differ diff --git a/Shaders/alpha_as_luma.hlsl b/Shaders/alpha_as_luma.hlsl new file mode 100644 index 0000000..525f3c6 --- /dev/null +++ b/Shaders/alpha_as_luma.hlsl @@ -0,0 +1,58 @@ +// https://stackoverflow.com/a/37624009 +float inverseGamma(float t) +{ + return ((t <= 0.0404482362771076) ? (t/12.92) : pow((t + 0.055)/1.055, 2.4)); +} + +// CIE L*a*b* f function (used to convert XYZ to L*a*b*) +// http://en.wikipedia.org/wiki/Lab_color_space +float LABF(float t) +{ + return ((t >= 8.85645167903563082e-3) ? pow(t, (1.0/3.0)) : (841.0/108.0)*t + (4.0/29.0)); +} + +float rgbToCIEL(float3 p) +{ + float r = inverseGamma(p.r); + float g = inverseGamma(p.g); + float b = inverseGamma(p.b); + + // Observer = 2°, Illuminant = D65 + float y = 0.2125862307855955516*r + 0.7151703037034108499*g + 0.07220049864333622685*b; + + // At this point we've done RGBtoXYZ now do XYZ to Lab + + // y /= WHITEPOINT_Y; The white point for y in D65 is 1.0 + y = LABF(y); + + // This is the "normal" conversion which produces values scaled to 100 + // Lab.L = 116.0*y - 16.0; + return 1.16*y - 0.16; +} + +// ---- Created with 3Dmigoto v1.4.9 on Sun Jun 28 13:42:41 2026 + +cbuffer CBSystem : register(b3) +{ + uint4 iRegion : packoffset(c0); + float fSourceMipLevel : packoffset(c1) = {0}; + float fGammaCorrect : packoffset(c1.y) = {0.454545468}; + float fGammaCorrectEx : packoffset(c1.z) = {1}; +} + +SamplerState SSSystemCopy : register(s0); +Texture2D tBaseMap : register(t0); + +void main( + float4 v0 : SV_POSITION0, + float2 v1 : TexCoord0, + out float4 o0 : SV_TARGET0) +{ + float4 r0; + r0.xyz = tBaseMap.SampleLevel(SSSystemCopy, v1.xy, fSourceMipLevel).xyz; + o0.w = rgbToCIEL(r0.xyz); + //o0.w = sqrt(dot(r0.xyz, float3(0.298999995, 0.587000012, 0.114))); + //o0.w = dot(r0.xyz, float3(0.298999995, 0.587000012, 0.114)); + o0.xyz = r0.xyz; + return; +} -- cgit v1.2.3-101-g0448