Skip to content

Commit dad90be

Browse files
committed
Added autoexposure support for cBloom
1 parent 4f1c053 commit dad90be

File tree

5 files changed

+117
-105
lines changed

5 files changed

+117
-105
lines changed

shaders/cAutoExposure.fx

Lines changed: 6 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "shared/cMacros.fxh"
22
#include "shared/cGraphics.fxh"
3+
#include "shared/cCamera.fxh"
34
#include "shared/cTonemap.fxh"
45

56
/*
@@ -12,23 +13,6 @@
1213

1314
uniform float _Frametime < source = "frametime"; >;
1415

15-
uniform float _SmoothingSpeed <
16-
ui_category = "Exposure";
17-
ui_label = "Smoothing";
18-
ui_type = "drag";
19-
ui_tooltip = "Exposure time smoothing";
20-
ui_min = 0.0;
21-
ui_max = 10.0;
22-
> = 1.0;
23-
24-
uniform float _ManualBias <
25-
ui_category = "Exposure";
26-
ui_label = "Exposure";
27-
ui_type = "drag";
28-
ui_tooltip = "Optional manual bias ";
29-
ui_min = 0.0;
30-
> = 1.0;
31-
3216
uniform float _Scale <
3317
ui_category = "Spot Metering";
3418
ui_label = "Area Scale";
@@ -67,54 +51,29 @@ CREATE_SAMPLER(SampleLumaTex, LumaTex, LINEAR, CLAMP)
6751

6852
/*
6953
[Pixel Shaders]
70-
---
71-
AutoExposure(): https://john-chapman.github.io/2017/08/23/dynamic-local-exposure.html
7254
*/
7355

74-
float2 Expand(float2 X)
75-
{
76-
return (X * 2.0) - 1.0;
77-
}
78-
79-
float2 Contract(float2 X)
80-
{
81-
return (X * 0.5) + 0.5;
82-
}
83-
8456
float4 PS_Blit(VS2PS_Quad Input) : SV_TARGET0
8557
{
8658
float2 Tex = Input.Tex0;
8759

8860
if (_Meter == 1)
8961
{
90-
Tex = Expand(Tex);
62+
Tex = (Tex * 2.0) - 1.0;
9163
Tex.x /= ASPECT_RATIO;
9264
Tex = (Tex * _Scale) + float2(_Offset.x, -_Offset.y);
93-
Tex = Contract(Tex);
65+
Tex = (Tex * 0.5) + 0.5;
9466
}
9567

9668
float4 Color = tex2D(CShade_SampleColorTex, Tex);
97-
float3 Luma = max(Color.r, max(Color.g, Color.b));
98-
99-
// OutputColor0.rgb = Output the highest brightness out of red/green/blue component
100-
// OutputColor0.a = Output the weight for temporal blending
101-
float Delay = 1e-3 * _Frametime;
102-
return float4(log(max(Luma.rgb, 1e-2)), saturate(Delay * _SmoothingSpeed));
103-
}
104-
105-
float3 GetAutoExposure(float3 Color, float2 Tex)
106-
{
107-
float LumaAverage = exp(tex2Dlod(SampleLumaTex, float4(Tex, 0.0, 99.0)).r);
108-
float Ev100 = log2(LumaAverage * 100.0 / 12.5);
109-
Ev100 -= _ManualBias; // optional manual bias
110-
float Exposure = 1.0 / (1.2 * exp2(Ev100));
111-
return Color * Exposure;
69+
return CreateExposureTex(Color.rgb, _Frametime);
11270
}
11371

11472
float3 PS_Exposure(VS2PS_Quad Input) : SV_TARGET0
11573
{
11674
float4 Color = tex2D(CShade_SampleColorTex, Input.Tex0);
117-
float3 ExposedColor = GetAutoExposure(Color.rgb, Input.Tex0);
75+
float Luma = tex2Dlod(SampleLumaTex, float4(Tex, 0.0, 99.0)).r;
76+
float3 ExposedColor = ApplyAutoExposure(Color.rgb, Luma, _ManualBias);
11877

11978
if (_Debug)
12079
{

shaders/cBloom.fx

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,65 @@
1+
12
#include "shared/cBuffers.fxh"
23
#include "shared/cGraphics.fxh"
4+
#include "shared/cCamera.fxh"
35
#include "shared/cTonemap.fxh"
46

57
/*
68
[Shader Options]
79
*/
810

11+
uniform float _Frametime < source = "frametime"; >;
12+
913
uniform float _Threshold <
10-
ui_category = "Bloom";
14+
ui_category = "Input Settings";
1115
ui_label = "Threshold";
1216
ui_type = "slider";
1317
ui_min = 0.0;
1418
ui_max = 1.0;
1519
> = 0.8;
1620

1721
uniform float _Smooth <
18-
ui_category = "Bloom";
22+
ui_category = "Input Settings";
1923
ui_label = "Smoothing";
2024
ui_type = "slider";
2125
ui_min = 0.0;
2226
ui_max = 1.0;
2327
> = 0.5;
2428

2529
uniform float _Saturation <
26-
ui_category = "Bloom";
30+
ui_category = "Input Settings";
2731
ui_label = "Saturation";
2832
ui_type = "slider";
2933
ui_min = 0.0;
3034
ui_max = 10.0;
3135
> = 1.0;
3236

3337
uniform float3 _ColorShift <
34-
ui_category = "Bloom";
38+
ui_category = "Input Settings";
3539
ui_label = "Color Shift (RGB)";
3640
ui_type = "color";
3741
ui_min = 0.0;
3842
ui_max = 1.0;
3943
> = 1.0;
4044

4145
uniform float _Intensity <
42-
ui_category = "Bloom";
46+
ui_category = "Input Settings";
4347
ui_label = "Intensity";
4448
ui_type = "slider";
4549
ui_min = 0.0;
4650
ui_max = 10.0;
47-
> = 5.0;
51+
> = 1.0;
52+
4853

4954
/*
5055
[Textures & Samplers]
5156
*/
5257

58+
#if USE_AUTOEXPOSURE
59+
CREATE_TEXTURE(ExposureTex, int2(1, 1), R16F, 0)
60+
CREATE_SAMPLER(SampleExposureTex, ExposureTex, LINEAR, CLAMP)
61+
#endif
62+
5363
CREATE_SAMPLER(SampleTempTex0, TempTex0_RGB10A2, LINEAR, CLAMP)
5464
CREATE_SAMPLER(SampleTempTex1, TempTex1_RGBA16F, LINEAR, CLAMP)
5565
CREATE_SAMPLER(SampleTempTex2, TempTex2_RGBA16F, LINEAR, CLAMP)
@@ -60,6 +70,7 @@ CREATE_SAMPLER(SampleTempTex6, TempTex6_RGBA16F, LINEAR, CLAMP)
6070
CREATE_SAMPLER(SampleTempTex7, TempTex7_RGBA16F, LINEAR, CLAMP)
6171
CREATE_SAMPLER(SampleTempTex8, TempTex8_RGBA16F, LINEAR, CLAMP)
6272

73+
6374
/*
6475
[Pixel Shaders]
6576
---
@@ -82,8 +93,15 @@ float4 PS_Prefilter(VS2PS_Quad Input) : SV_TARGET0
8293
{
8394
const float Knee = mad(_Threshold, _Smooth, 1e-5);
8495
const float3 Curve = float3(_Threshold - Knee, Knee * 2.0, 0.25 / Knee);
96+
8597
float4 Color = tex2D(CShade_SampleColorTex, Input.Tex0);
8698

99+
#if USE_AUTOEXPOSURE
100+
// Apply auto-exposure here
101+
float Luma = tex2D(SampleExposureTex, Input.Tex0).r;
102+
Color = ApplyAutoExposure(Color.rgb, Luma);
103+
#endif
104+
87105
// Under-threshold
88106
float Brightness = Med3(Color.r, Color.g, Color.b);
89107
float Response_Curve = clamp(Brightness - Curve.x, 0.0, Curve.y);
@@ -220,9 +238,14 @@ CREATE_PS_DOWNSCALE(PS_Downscale6, SampleTempTex5, false)
220238
CREATE_PS_DOWNSCALE(PS_Downscale7, SampleTempTex6, false)
221239
CREATE_PS_DOWNSCALE(PS_Downscale8, SampleTempTex7, false)
222240

223-
float4 GetPixelUpscale(VS2PS_Quad Input, sampler2D SampleSource)
241+
float4 PS_GetExposure(VS2PS_Quad Input) : SV_TARGET0
224242
{
243+
float4 Color = tex2D(SampleTempTex8, Input.Tex0);
244+
return CreateExposureTex(Color.rgb, _Frametime);
245+
}
225246

247+
float4 GetPixelUpscale(VS2PS_Quad Input, sampler2D SampleSource)
248+
{
226249
// A0 B0 C0
227250
// A1 B1 C1
228251
// A2 B2 C2
@@ -265,16 +288,6 @@ CREATE_PS_UPSCALE(PS_Upscale3, SampleTempTex4)
265288
CREATE_PS_UPSCALE(PS_Upscale2, SampleTempTex3)
266289
CREATE_PS_UPSCALE(PS_Upscale1, SampleTempTex2)
267290

268-
float3 ToneMapACESFilmic(float3 x)
269-
{
270-
float a = 2.51;
271-
float b = 0.03;
272-
float c = 2.43;
273-
float d = 0.59;
274-
float e = 0.14;
275-
return saturate((x * (a * x + b)) / (x * (c * x + d) + e));
276-
}
277-
278291
float4 PS_Composite(VS2PS_Quad Input) : SV_TARGET0
279292
{
280293
float3 BaseColor = tex2D(CShade_SampleColorTex, Input.Tex0).rgb;
@@ -311,6 +324,22 @@ technique CShade_Bloom
311324
CREATE_PASS(VS_Quad, PS_Downscale7, TempTex7_RGBA16F, FALSE)
312325
CREATE_PASS(VS_Quad, PS_Downscale8, TempTex8_RGBA16F, FALSE)
313326

327+
#if USE_AUTOEXPOSURE
328+
pass CreateExposureTex
329+
{
330+
ClearRenderTargets = FALSE;
331+
BlendEnable = TRUE;
332+
BlendOp = ADD;
333+
SrcBlend = SRCALPHA;
334+
DestBlend = INVSRCALPHA;
335+
336+
VertexShader = VS_Quad;
337+
PixelShader = PS_GetExposure;
338+
339+
RenderTarget0 = ExposureTex;
340+
}
341+
#endif
342+
314343
CREATE_PASS(VS_Quad, PS_Upscale7, TempTex7_RGBA16F, TRUE)
315344
CREATE_PASS(VS_Quad, PS_Upscale6, TempTex6_RGBA16F, TRUE)
316345
CREATE_PASS(VS_Quad, PS_Upscale5, TempTex5_RGBA16F, TRUE)

shaders/cMedian.fx

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,5 @@
11
#include "shared/cGraphics.fxh"
22

3-
/*
4-
[Vertex Shaders]
5-
*/
6-
7-
struct VS2PS_Median
8-
{
9-
float4 HPos : SV_POSITION;
10-
float4 Tex0 : TEXCOORD0;
11-
float4 Tex1 : TEXCOORD1;
12-
float4 Tex2 : TEXCOORD2;
13-
};
14-
15-
VS2PS_Median VS_Median(APP2VS Input)
16-
{
17-
float2 PixelSize = 1.0 / (float2(BUFFER_WIDTH, BUFFER_HEIGHT));
18-
19-
VS2PS_Quad FSQuad = VS_Quad(Input);
20-
21-
VS2PS_Median Output;
22-
Output.HPos = FSQuad.HPos;
23-
Output.Tex0 = FSQuad.Tex0.xyyy + (float4(-1.0, 1.0, 0.0, -1.0) * PixelSize.xyyy);
24-
Output.Tex1 = FSQuad.Tex0.xyyy + (float4(0.0, 1.0, 0.0, -1.0) * PixelSize.xyyy);
25-
Output.Tex2 = FSQuad.Tex0.xyyy + (float4(1.0, 1.0, 0.0, -1.0) * PixelSize.xyyy);
26-
return Output;
27-
}
28-
293
/*
304
[Pixel Shaders]
315
---
@@ -59,20 +33,25 @@ float4 Med9(float4 X0, float4 X1, float4 X2,
5933

6034
float4 PS_Median(VS2PS_Median Input) : SV_TARGET0
6135
{
36+
float2 PixelSize = fwidth(Input.Tex0.xy);
37+
float4 Tex0 = Input.Tex0.xyyy + (float4(-1.0, 1.0, 0.0, -1.0) * PixelSize.xyyy);
38+
float4 Tex1 = Input.Tex0.xyyy + (float4(0.0, 1.0, 0.0, -1.0) * PixelSize.xyyy);
39+
float4 Tex2 = Input.Tex0.xyyy + (float4(1.0, 1.0, 0.0, -1.0) * PixelSize.xyyy);
40+
6241
// Sample locations:
6342
// [0].xy [1].xy [2].xy
6443
// [0].xz [1].xz [2].xz
6544
// [0].xw [1].xw [2].xw
6645
float4 Sample[9];
67-
Sample[0] = tex2D(CShade_SampleColorTex, Input.Tex0.xy);
68-
Sample[1] = tex2D(CShade_SampleColorTex, Input.Tex1.xy);
69-
Sample[2] = tex2D(CShade_SampleColorTex, Input.Tex2.xy);
70-
Sample[3] = tex2D(CShade_SampleColorTex, Input.Tex0.xz);
71-
Sample[4] = tex2D(CShade_SampleColorTex, Input.Tex1.xz);
72-
Sample[5] = tex2D(CShade_SampleColorTex, Input.Tex2.xz);
73-
Sample[6] = tex2D(CShade_SampleColorTex, Input.Tex0.xw);
74-
Sample[7] = tex2D(CShade_SampleColorTex, Input.Tex1.xw);
75-
Sample[8] = tex2D(CShade_SampleColorTex, Input.Tex2.xw);
46+
Sample[0] = tex2D(CShade_SampleColorTex, Tex0.xy);
47+
Sample[1] = tex2D(CShade_SampleColorTex, Tex1.xy);
48+
Sample[2] = tex2D(CShade_SampleColorTex, Tex2.xy);
49+
Sample[3] = tex2D(CShade_SampleColorTex, Tex0.xz);
50+
Sample[4] = tex2D(CShade_SampleColorTex, Tex1.xz);
51+
Sample[5] = tex2D(CShade_SampleColorTex, Tex2.xz);
52+
Sample[6] = tex2D(CShade_SampleColorTex, Tex0.xw);
53+
Sample[7] = tex2D(CShade_SampleColorTex, Tex1.xw);
54+
Sample[8] = tex2D(CShade_SampleColorTex, Tex2.xw);
7655
return Med9(Sample[0], Sample[1], Sample[2],
7756
Sample[3], Sample[4], Sample[5],
7857
Sample[6], Sample[7], Sample[8]);
@@ -84,7 +63,7 @@ technique CShade_Median
8463
{
8564
SRGBWriteEnable = WRITE_SRGB;
8665

87-
VertexShader = VS_Median;
66+
VertexShader = VS_Quad;
8867
PixelShader = PS_Median;
8968
}
9069
}

shaders/shared/cCamera.fxh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
#if !defined(INCLUDE_CAMERA)
3+
#define INCLUDE_CAMERA
4+
5+
// AutoExposure(): https://john-chapman.github.io/2017/08/23/dynamic-local-exposure.html
6+
7+
uniform float _CShadeExposureBias <
8+
ui_category = "Output: AutoExposure";
9+
ui_label = "Exposure bias";
10+
ui_tooltip = "Optional manual bias ";
11+
ui_type = "drag";
12+
ui_step = 0.001;
13+
ui_min = 0.0;
14+
ui_max = 10.0;
15+
> = 0.0;
16+
17+
uniform float _CShadeExposureSmoothingSpeed <
18+
ui_category = "Output: AutoExposure";
19+
ui_label = "Smoothing";
20+
ui_type = "drag";
21+
ui_tooltip = "Exposure time smoothing";
22+
ui_min = 0.001;
23+
ui_max = 1.0;
24+
> = 1.0;
25+
26+
float4 CreateExposureTex(float3 Color, float FrameTime)
27+
{
28+
float3 Luma = max(Color.r, max(Color.g, Color.b));
29+
30+
// .rgb = Output the highest brightness out of red/green/blue component
31+
// .a = Output the weight for temporal blending
32+
float Delay = 1e-3 * FrameTime;
33+
return float4(log(max(Luma, 1e-2)), saturate(Delay * _CShadeExposureSmoothingSpeed));
34+
}
35+
36+
float3 ApplyAutoExposure(float3 Color, float Luma)
37+
{
38+
float LumaAverage = exp(Luma);
39+
float Ev100 = log2(LumaAverage * 100.0 / 12.5);
40+
Ev100 -= _CShadeExposureBias; // optional manual bias
41+
float Exposure = 1.0 / (1.2 * exp2(Ev100));
42+
return Color * Exposure;
43+
}
44+
45+
#endif

shaders/shared/cTonemap.fxh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,17 @@
8080
return 0.5 * (D * SDR - sqrt(((D*D - 4.0*C*E) * SDR + 4.0*A*E-2.0*B*D) * SDR + B*B) - B) / (A - C * SDR);
8181
}
8282

83-
uniform int _OutputTonemapOperator <
84-
ui_category = "OUTPUT";
83+
uniform int _CShadeTonemapOperator <
84+
ui_category = "Output: Tonemapping";
8585
ui_label = "Tonemap Operator";
8686
ui_tooltip = "Select a tonemap operator for the output";
8787
ui_type = "combo";
88-
ui_items = "Reinhard\0DirectX Graphics Sample\0ACES Filmic Approximation\0";
89-
> = 0;
88+
ui_items = "Reinhard\0DirectX Graphics Tonemap\0ACES Filmic Approximation\0";
89+
> = 1;
9090

9191
float3 ApplyTonemap(float3 HDR)
9292
{
93-
switch (_OutputTonemapOperator)
93+
switch (_CShadeTonemapOperator)
9494
{
9595
case 0:
9696
return ApplyReinhardTonemap(HDR, 1.0);

0 commit comments

Comments
 (0)