• Hi Guest!

    We have posted a new VaM2 dev log on Patreon, starting a monthly cadence of written progress updates between Beta releases. Highlights include the new Gizmos System, Selection Carousel, and Modes System with Context-Specific Editing. Beta1.2 is 15 of 21 items complete.

    Read the full post on Patreon, or follow progress on the public Trello roadmap.

VaM 1.x Figured out how to enable HDR tonemapping, but don't know how to mod it in.

Threads regarding the original VaM 1.x

SmutSmith

Member
Joined
Jul 6, 2021
Messages
47
Reactions
32
Using RenderDoc to inspect a frame from the game, I discovered that before the final render texture is generated, there's a 16 bit per channel floating point render texture generated, which is then passed through a pixel shader to map the values to an 8 bit colorspace, with no correction, leading to the primitive-looking saturated overbrights.

The shader responsible is called Hidden/BlitCopy:
// HLSL function stub generated

SamplerState sampler0 : register(s0); // can't disambiguate
//SamplerComparisonState sampler0 : register(s0); // can't disambiguate
Texture2D<float4> texture0 : register(t0);


cbuffer cbuffer0 : register(b0) {
float4 cb0_v0 : packoffset(c0.x);
float4 cb0_v1 : packoffset(c1.x);
float4 cb0_v2 : packoffset(c2.x);
float4 cb0_v3 : packoffset(c3.x);
};



struct InputStruct {
float4 Position : SV_Position;
float2 param1 : TEXCOORD;
};

struct OutputStruct {
float4 Target0 : SV_Target0;
};

OutputStruct EditedShaderPS(in InputStruct IN)
{
OutputStruct OUT = (OutputStruct)0;

// ...

return OUT;
}



If you simply change it to:


// HLSL function stub generated

SamplerState sampler0 : register(s0); // can't disambiguate
//SamplerComparisonState sampler0 : register(s0); // can't disambiguate
Texture2D<float4> texture0 : register(t0);


cbuffer cbuffer0 : register(b0) {
float4 cb0_v0 : packoffset(c0.x);
float4 cb0_v1 : packoffset(c1.x);
float4 cb0_v2 : packoffset(c2.x);
float4 cb0_v3 : packoffset(c3.x);
};



struct InputStruct {
float4 Position : SV_Position;
float2 param1 : TEXCOORD;
};

struct OutputStruct {
float4 Target0 : SV_Target0;
};

OutputStruct EditedShaderPS(in InputStruct IN)
{
OutputStruct OUT = (OutputStruct)0;

float4 hdr = texture0.Sample(sampler0, IN.param1);

// Preserve the existing Unity blit multiplier
hdr *= cb0_v3;

// Simple Reinhard tone mapping
float3 mapped = hdr.rgb / (hdr.rgb + 1.0);

OUT.Target0 = float4(mapped, hdr.a);

return OUT;
}


The overbrights are clamped and it looks a hundred times better.

Another option is an ACES tonemap:

// HLSL function stub generated

SamplerState sampler0 : register(s0);
Texture2D<float4> texture0 : register(t0);

cbuffer cbuffer0 : register(b0) {
float4 cb0_v0 : packoffset(c0.x);
float4 cb0_v1 : packoffset(c1.x);
float4 cb0_v2 : packoffset(c2.x);
float4 cb0_v3 : packoffset(c3.x);
};

struct InputStruct {
float4 Position : SV_Position;
float2 param1 : TEXCOORD;
};

struct OutputStruct {
float4 Target0 : SV_Target0;
};


// Add this function here:
float3 ACESFilm(float3 x)
{
float a = 2.51;
float b = 0.03;
float c = 2.43;
float d = 0.59;
float e = 0.14;

return saturate((x*(a*x+b))/(x*(c*x+d)+e));
}


// Replace the entire EditedShaderPS function:
OutputStruct EditedShaderPS(in InputStruct IN)
{
OutputStruct OUT = (OutputStruct)0;

float4 hdr = texture0.Sample(sampler0, IN.param1);

// Keep Unity's original multiplier
hdr *= cb0_v3;

float3 mapped = ACESFilm(hdr.rgb);

OUT.Target0 = float4(mapped, hdr.a);

return OUT;
}



Here's some comparisons generated in Renderdoc (I don't have the knowledge to implement this into the game)

ORIGINAL
withoutHDR.png



WITH CLAMPING
withHDR.png


WITH ACES TONEMAP
ACES.png


If anyone can make this into a plugin or mod of some sort, it could make the game look incredible.
 
Back
Top Bottom