-
Notifications
You must be signed in to change notification settings - Fork 99
Expand file tree
/
Copy pathToneMappingUtility.hlsli
More file actions
130 lines (106 loc) · 3.61 KB
/
ToneMappingUtility.hlsli
File metadata and controls
130 lines (106 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
// Developed by Minigraph
//
// Author: James Stanard
//
#ifndef __TONE_MAPPING_UTILITY_HLSLI__
#define __TONE_MAPPING_UTILITY_HLSLI__
#include "ShaderUtility.hlsli"
//
// Reinhard
//
// The Reinhard tone operator. Typically, the value of k is 1.0, but you can adjust exposure by 1/k.
// I.e. TM_Reinhard(x, 0.5) == TM_Reinhard(x * 2.0, 1.0)
float3 TM_Reinhard(float3 hdr, float k = 1.0)
{
return hdr / (hdr + k);
}
// The inverse of Reinhard
float3 ITM_Reinhard(float3 sdr, float k = 1.0)
{
return k * sdr / (1.0 - sdr);
}
//
// Reinhard-Squared
//
// This has some nice properties that improve on basic Reinhard. Firstly, it has a "toe"--that nice,
// parabolic upswing that enhances contrast and color saturation in darks. Secondly, it has a long
// shoulder giving greater detail in highlights and taking longer to desaturate. It's invertible, scales
// to HDR displays, and is easy to control.
//
// The default constant of 0.25 was chosen for two reasons. It maps closely to the effect of Reinhard
// with a constant of 1.0. And with a constant of 0.25, there is an inflection point at 0.25 where the
// curve touches the line y=x and then begins the shoulder.
//
// Note: If you are currently using ACES and you pre-scale by 0.6, then k=0.30 looks nice as an alternative
// without any other adjustments.
float3 TM_ReinhardSq(float3 hdr, float k = 0.25)
{
float3 reinhard = hdr / (hdr + k);
return reinhard * reinhard;
}
float3 ITM_ReinhardSq(float3 sdr, float k = 0.25)
{
return k * (sdr + sqrt(sdr)) / (1.0 - sdr);
}
//
// Stanard (New)
//
// This is the new tone operator. It resembles ACES in many ways, but it is simpler to evaluate with ALU. One
// advantage it has over Reinhard-Squared is that the shoulder goes to white more quickly and gives more overall
// brightness and contrast to the image.
float3 TM_Stanard(float3 hdr)
{
return TM_Reinhard(hdr * sqrt(hdr), sqrt(4.0 / 27.0));
}
float3 ITM_Stanard(float3 sdr)
{
return pow(ITM_Reinhard(sdr, sqrt(4.0 / 27.0)), 2.0 / 3.0);
}
//
// Stanard (Old)
//
// This is the old tone operator first used in HemiEngine and then MiniEngine. It's simplistic, efficient,
// invertible, and gives nice results, but it has no toe, and the shoulder goes to white fairly quickly.
//
// Note that I removed the distinction between tone mapping RGB and tone mapping Luma. Philosophically, I
// agree with the idea of trying to remap brightness to displayable values while preserving hue. But you
// run into problems where one or more color channels end up brighter than 1.0 and get clipped.
float3 ToneMap( float3 hdr )
{
return 1 - exp2(-hdr);
}
float3 InverseToneMap(float3 sdr)
{
return -log2(max(1e-6, 1 - sdr));
}
float ToneMapLuma( float luma )
{
return 1 - exp2(-luma);
}
float InverseToneMapLuma(float luma)
{
return -log2(max(1e-6, 1 - luma));
}
//
// ACES
//
// The next generation of filmic tone operators.
float3 ToneMapACES( float3 hdr )
{
const float A = 2.51, B = 0.03, C = 2.43, D = 0.59, E = 0.14;
return saturate((hdr * (A * hdr + B)) / (hdr * (C * hdr + D) + E));
}
float3 InverseToneMapACES( float3 sdr )
{
const float A = 2.51, B = 0.03, C = 2.43, D = 0.59, E = 0.14;
return 0.5 * (D * sdr - sqrt(((D*D - 4*C*E) * sdr + 4*A*E-2*B*D) * sdr + B*B) - B) / (A - C * sdr);
}
#endif // __TONE_MAPPING_UTILITY_HLSLI__