three_d/renderer/viewer/tone_mapping.rs
1use crate::core::*;
2
3///
4/// Tone mapping is the process of mapping HDR color values computed with physical based rendering in the range `[0,∞)`
5/// into LDR values that can be displayed on the screen in the range `[0,1]`.
6///
7#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
8pub enum ToneMapping {
9    /// No tone mapping. Use this if you are rendering into an intermediate render target, ie. this is not the final render pass that renders into the screen.
10    None = 0,
11    /// Photographic Tone Reproduction for Digital Images. `<http://www.cmap.polytechnique.fr/~peyre/cours/x2005signal/hdr_photographic.pdf>`
12    Reinhard = 1,
13    /// ACES Filmic Tone Mapping Curve. `<https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/>`
14    #[default]
15    Aces = 2,
16    /// John Hables presentation "Uncharted 2 HDR Lighting", Page 142 to 143. `<http://www.gdcvault.com/play/1012459/Uncharted_2__HDR_Lighting>`
17    Filmic = 3,
18}
19
20impl ToneMapping {
21    ///
22    /// Returns the fragment shader source for applying the specified tone mapping in a shader.
23    ///
24    pub fn fragment_shader_source() -> &'static str {
25        "
26        uniform uint toneMappingType;
27
28        vec3 tone_mapping(vec3 color) {
29            if (toneMappingType == 1u) {
30                color = color / (color + vec3(1.0));
31                color = clamp(color, 0.0, 1.0);
32            } else if(toneMappingType == 2u) {
33                color = color*(2.51*color + .03) / (color*(2.43*color + .59) + .14);
34                color = clamp(color, 0.0, 1.0);
35            } else if(toneMappingType == 3u) {
36                const float A = 0.15;
37                const float B = 0.50;
38                const float C = 0.10;
39                const float D = 0.20;
40                const float E = 0.02;
41                const float F = 0.30;
42                const float W = 11.2;
43                
44                vec4 x = vec4(color, W);
45                x = ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
46                color = x.xyz / x.w;
47                color = clamp(color, 0.0, 1.0);
48            }
49            return color;
50        }
51        "
52    }
53
54    ///
55    /// Sends the uniform data needed to apply this tone mapping to the fragment shader.
56    ///
57    pub fn use_uniforms(&self, program: &Program) {
58        program.use_uniform("toneMappingType", *self as u32);
59    }
60}