Skip to content

Commit

Permalink
Add a few different tonemapper options
Browse files Browse the repository at this point in the history
Process imgui input before beginning imgui frame (ocornut/imgui#3575)
  • Loading branch information
kabergstrom committed Mar 28, 2021
1 parent 7ecbe82 commit 9771763
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 26 deletions.
Binary file modified demo/assets/shaders/bloom_combine.frag.cookedshaderpackage
Binary file not shown.
107 changes: 105 additions & 2 deletions demo/shaders/generated_msl/bloom_combine.frag.metal
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
#pragma clang diagnostic ignored "-Wmissing-prototypes"

#include <metal_stdlib>
#include <simd/simd.h>

using namespace metal;

struct Config
{
int tonemapper_type;
};

struct spvDescriptorSetBuffer0
{
texture2d<float> in_color [[id(0)]];
texture2d<float> in_blur [[id(1)]];
constant Config* config [[id(3)]];
};

struct main0_out
Expand All @@ -19,13 +27,108 @@ struct main0_in
float2 inUV [[user(locn0)]];
};

static inline __attribute__((always_inline))
float3 RRT_and_ODT_fit(thread const float3& v)
{
float3 a = (v * (v + float3(0.02457859925925731658935546875))) - float3(9.0537003416102379560470581054688e-05);
float3 b = (v * ((v * 0.98372900485992431640625) + float3(0.4329510033130645751953125))) + float3(0.23808099329471588134765625);
return a / b;
}

static inline __attribute__((always_inline))
float3 tonemap_aces_fitted(thread float3& color)
{
color = float3x3(float3(0.59719002246856689453125, 0.354579985141754150390625, 0.048229999840259552001953125), float3(0.075999997556209564208984375, 0.908339977264404296875, 0.0156599991023540496826171875), float3(0.0284000001847743988037109375, 0.13382999598979949951171875, 0.837769985198974609375)) * color;
float3 param = color;
color = RRT_and_ODT_fit(param);
color = float3x3(float3(1.60475003719329833984375, -0.5310800075531005859375, -0.0736699998378753662109375), float3(-0.10208000242710113525390625, 1.108129978179931640625, -0.00604999996721744537353515625), float3(-0.00326999998651444911956787109375, -0.07276000082492828369140625, 1.0760200023651123046875)) * color;
color = fast::clamp(color, float3(0.0), float3(1.0));
return color;
}

static inline __attribute__((always_inline))
float3 tonemap_aces_film_simple(thread const float3& x)
{
float a = 2.5099999904632568359375;
float b = 0.02999999932944774627685546875;
float c = 2.4300000667572021484375;
float d = 0.589999973773956298828125;
float e = 0.14000000059604644775390625;
return fast::clamp((x * ((x * a) + float3(b))) / ((x * ((x * c) + float3(d))) + float3(e)), float3(0.0), float3(1.0));
}

static inline __attribute__((always_inline))
float3 visualize_value(thread const float& val)
{
float g = 1.0 - ((0.20000000298023223876953125 * (val - 3.2360498905181884765625)) * (val - 3.2360498905181884765625));
float b = 1.0 - ((1.0 * (val - 1.0)) * (val - 1.0));
float r = 1.0 - (1.0 / ((0.5 * val) - 0.5));
if (val > 1.0)
{
b = 0.0;
}
if (val < 3.0)
{
r = 0.0;
}
return fast::clamp(float3(r, g, b), float3(0.0), float3(1.0));
}

static inline __attribute__((always_inline))
float luma(thread const float3& color)
{
return dot(color, float3(0.2989999949932098388671875, 0.58700001239776611328125, 0.114000000059604644775390625));
}

fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
constexpr sampler smp(mip_filter::linear, compare_func::never, max_anisotropy(1));
main0_out out = {};
float4 color = spvDescriptorSet0.in_color.sample(smp, in.inUV) + spvDescriptorSet0.in_blur.sample(smp, in.inUV);
float3 mapped = color.xyz / (color.xyz + float3(1.0));
out.out_sdr = float4(mapped, color.w);
if ((*spvDescriptorSet0.config).tonemapper_type == 1)
{
float3 param = color.xyz;
float3 _227 = tonemap_aces_fitted(param);
out.out_sdr = float4(_227, color.w);
}
else
{
if ((*spvDescriptorSet0.config).tonemapper_type == 2)
{
float3 param_1 = color.xyz;
out.out_sdr = float4(tonemap_aces_film_simple(param_1), color.w);
}
else
{
if ((*spvDescriptorSet0.config).tonemapper_type == 3)
{
out.out_sdr = float4(color.xyz / (color.xyz + float3(1.0)), color.w);
}
else
{
if ((*spvDescriptorSet0.config).tonemapper_type == 4)
{
float max_val = fast::max(color.x, fast::max(color.y, color.z));
float param_2 = max_val;
out.out_sdr = float4(visualize_value(param_2), color.w);
}
else
{
if ((*spvDescriptorSet0.config).tonemapper_type == 5)
{
float3 param_3 = color.xyz;
float l = luma(param_3);
float param_4 = l;
out.out_sdr = float4(visualize_value(param_4), color.w);
}
else
{
out.out_sdr = color;
}
}
}
}
}
return out;
}

98 changes: 96 additions & 2 deletions demo/shaders/glsl/bloom_combine.frag
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,109 @@ layout (set = 0, binding = 1) uniform texture2D in_blur;
// ])]
layout (set = 0, binding = 2) uniform sampler smp;

// @[export]
// @[internal_buffer]
layout (set = 0, binding = 3) uniform Config {
int tonemapper_type;
} config;

layout (location = 0) in vec2 inUV;

layout (location = 0) out vec4 out_sdr;

// The code for ACESFitted was originally written by Stephen Hill (@self_shadow), who deserves all
// credit for coming up with this fit and implementing it. Buy him a beer next time you see him. :)
// The code is licensed under the MIT license

// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT
const mat3 ACESInputMat =
{
{0.59719, 0.35458, 0.04823},
{0.07600, 0.90834, 0.01566},
{0.02840, 0.13383, 0.83777}
};

// ODT_SAT => XYZ => D60_2_D65 => sRGB
const mat3 ACESOutputMat =
{
{ 1.60475, -0.53108, -0.07367},
{-0.10208, 1.10813, -0.00605},
{-0.00327, -0.07276, 1.07602}
};

vec3 RRT_and_ODT_fit(vec3 v)
{
vec3 a = v * (v + 0.0245786f) - 0.000090537f;
vec3 b = v * (0.983729f * v + 0.4329510f) + 0.238081f;
return a / b;
}

vec3 tonemap_aces_fitted(vec3 color)
{
color = ACESInputMat * color;

// Apply RRT and ODT
color = RRT_and_ODT_fit(color);

color = ACESOutputMat * color;

// Clamp to [0, 1]
color = clamp(color, 0, 1);

return color;
}

// source: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
vec3 tonemap_aces_film_simple(vec3 x)
{
float a = 2.51f;
float b = 0.03f;
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
return clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0);
}

float luma(vec3 color) {
return dot(color, vec3(0.299, 0.587, 0.114));
}

vec3 visualize_value(float val) {
// parabolic curves visualize the range
// blue is used to visualize 0-1 exclusively
// green covers 0-5
// red is 3+
float g = 1 - 0.2 * (val - 3.23605) * (val - 3.23605);
float b = 1 - 1 * (val - 1) * (val - 1);
float r = 1 - 1 / (0.5 * val - 0.5);
if (val > 1.0) {
b = 0;
}
if (val < 3.0) {
r = 0;
}
return clamp(vec3(r, g, b), 0, 1);
}

void main()
{
vec4 color = texture(sampler2D(in_color, smp), inUV) + texture(sampler2D(in_blur, smp), inUV);

// tonemapping.. TODO: implement auto-exposure
vec3 mapped = color.rgb / (color.rgb + vec3(1.0));
out_sdr = vec4(mapped, color.a);
if (config.tonemapper_type == 1) {
out_sdr = vec4(tonemap_aces_fitted(color.rgb), color.a);
} else if (config.tonemapper_type == 2) {
out_sdr = vec4(tonemap_aces_film_simple(color.rgb), color.a);
} else if (config.tonemapper_type == 3) {
out_sdr = vec4(color.rgb / (color.rgb + vec3(1.0)), color.a);
} else if (config.tonemapper_type == 4) {
float max_val = max(color.r, max(color.g, color.b));
out_sdr = vec4(visualize_value(max_val), color.a);
} else if (config.tonemapper_type == 5) {
float l = luma(color.rgb);
out_sdr = vec4(visualize_value(l), color.a);
} else {
out_sdr = color;
}
// out_sdr = vec4(mapped, color.a);
}
10 changes: 0 additions & 10 deletions demo/shaders/glsl/mesh.frag
Original file line number Diff line number Diff line change
Expand Up @@ -885,16 +885,6 @@ vec4 pbr_path(
vec3 color = ambient + total_light + emissive_color.rgb;
#endif
return vec4(color, base_color.a);

// tonemapping
//vec3 mapped = color.rgb / (color.rgb + vec3(1.0));

// gamma correction
//const float gamma = 2.2;
//mapped = pow(mapped, vec3(1.0 / gamma));

// output
//return vec4(mapped, base_color.a);
}


Expand Down
47 changes: 47 additions & 0 deletions demo/shaders/src/bloom_combine_frag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,37 @@ use rafx_framework::{
ImageViewResource, ResourceArc,
};

#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct ConfigStd140 {
pub tonemapper_type: i32, // +0 (size: 4)
pub _padding0: [u8; 12], // +4 (size: 12)
} // 16 bytes

impl Default for ConfigStd140 {
fn default() -> Self {
ConfigStd140 {
tonemapper_type: <i32>::default(),
_padding0: [u8::default(); 12],
}
}
}

pub type ConfigUniform = ConfigStd140;

pub const IN_COLOR_DESCRIPTOR_SET_INDEX: usize = 0;
pub const IN_COLOR_DESCRIPTOR_BINDING_INDEX: usize = 0;
pub const IN_BLUR_DESCRIPTOR_SET_INDEX: usize = 0;
pub const IN_BLUR_DESCRIPTOR_BINDING_INDEX: usize = 1;
pub const SMP_DESCRIPTOR_SET_INDEX: usize = 0;
pub const SMP_DESCRIPTOR_BINDING_INDEX: usize = 2;
pub const CONFIG_DESCRIPTOR_SET_INDEX: usize = 0;
pub const CONFIG_DESCRIPTOR_BINDING_INDEX: usize = 3;

pub struct DescriptorSet0Args<'a> {
pub in_color: &'a ResourceArc<ImageViewResource>,
pub in_blur: &'a ResourceArc<ImageViewResource>,
pub config: &'a ConfigUniform,
}

impl<'a> DescriptorSetInitializer<'a> for DescriptorSet0Args<'a> {
Expand Down Expand Up @@ -53,6 +74,7 @@ impl DescriptorSet0 {
) {
descriptor_set.set_image(IN_COLOR_DESCRIPTOR_BINDING_INDEX as u32, args.in_color);
descriptor_set.set_image(IN_BLUR_DESCRIPTOR_BINDING_INDEX as u32, args.in_blur);
descriptor_set.set_buffer_data(CONFIG_DESCRIPTOR_BINDING_INDEX as u32, args.config);
}

pub fn set_args(
Expand All @@ -61,6 +83,7 @@ impl DescriptorSet0 {
) {
self.set_in_color(args.in_color);
self.set_in_blur(args.in_blur);
self.set_config(args.config);
}

pub fn set_in_color(
Expand All @@ -79,10 +102,34 @@ impl DescriptorSet0 {
.set_image(IN_BLUR_DESCRIPTOR_BINDING_INDEX as u32, in_blur);
}

pub fn set_config(
&mut self,
config: &ConfigUniform,
) {
self.0
.set_buffer_data(CONFIG_DESCRIPTOR_BINDING_INDEX as u32, config);
}

pub fn flush(
&mut self,
descriptor_set_allocator: &mut DescriptorSetAllocator,
) -> RafxResult<()> {
self.0.flush(descriptor_set_allocator)
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_struct_config_std140() {
assert_eq!(std::mem::size_of::<ConfigStd140>(), 16);
assert_eq!(std::mem::size_of::<i32>(), 4);
assert_eq!(std::mem::align_of::<i32>(), 4);
assert_eq!(memoffset::offset_of!(ConfigStd140, tonemapper_type), 0);
assert_eq!(std::mem::size_of::<[u8; 12]>(), 12);
assert_eq!(std::mem::align_of::<[u8; 12]>(), 1);
assert_eq!(memoffset::offset_of!(ConfigStd140, _padding0), 4);
}
}
Loading

0 comments on commit 9771763

Please sign in to comment.