From 7b6bda1188cf80ffc85b16e099d7811c92dbd7ac Mon Sep 17 00:00:00 2001 From: quou Date: Sat, 18 Jan 2025 17:35:27 +1100 Subject: tonemap --- Makefile | 10 ++-- c2.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++---- configure.lua | 1 + intermediate/tonemap.glsl | 85 +++++++++++++++++++++++++++++++++ todo.txt | 1 + 5 files changed, 203 insertions(+), 12 deletions(-) create mode 100644 intermediate/tonemap.glsl diff --git a/Makefile b/Makefile index b2fa152..8761134 100644 --- a/Makefile +++ b/Makefile @@ -101,12 +101,14 @@ data/surface.csh: intermediate/surface.glsl shadercompiler | data ./shadercompiler intermediate/surface.glsl data/surface.csh data/surface_depthonly.csh: intermediate/surface_depthonly.glsl shadercompiler | data ./shadercompiler intermediate/surface_depthonly.glsl data/surface_depthonly.csh +data/tonemap.csh: intermediate/tonemap.glsl shadercompiler | data + ./shadercompiler intermediate/tonemap.glsl data/tonemap.csh data/triangle.csh: intermediate/triangle.glsl shadercompiler | data ./shadercompiler intermediate/triangle.glsl data/triangle.csh data/ui.csh: intermediate/ui.glsl shadercompiler | data ./shadercompiler intermediate/ui.glsl data/ui.csh -data/monkey.mdl: convmodel intermediate/monkey.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/triangle.csh data/ui.csh | data +data/monkey.mdl: convmodel intermediate/monkey.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh | data ./convmodel data intermediate/monkey.glb data/monkey.mdl data/22.tex: convtexture intermediate/22.bmp | data @@ -127,8 +129,8 @@ data/bricks.mat: convmaterial intermediate/bricks.mat | data data/plastic.mat: convmaterial intermediate/plastic.mat | data ./convmaterial intermediate/plastic.mat data/plastic.mat -pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/triangle.csh data/ui.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat - ./packer pack data debug.csh mip_spec.csh sky.csh surface.csh surface_depthonly.csh triangle.csh ui.csh monkey.mdl 22.tex kita.tex brick_albedo.tex brick_ao.tex brick_normal.tex sky.tex bricks.mat plastic.mat +pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat + ./packer pack data debug.csh mip_spec.csh sky.csh surface.csh surface_depthonly.csh tonemap.csh triangle.csh ui.csh monkey.mdl 22.tex kita.tex brick_albedo.tex brick_ao.tex brick_normal.tex sky.tex bricks.mat plastic.mat data: mkdir -p data @@ -136,7 +138,7 @@ data: -include qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d maths.d model.d pipeline.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d clean: - rm -f qstd/memory.o qstd/plat.o qstd/str.o qstd/pack.o cfg/cfgparse.o sc/sc.o sc/includer.o app.o asset.o c2.o camera.o debugdraw.o editor.o maths.o model.o pipeline.o scene.o ui.o video.o world.o convtexture.o convmodel.o convmaterial.o packer.o qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d maths.d model.d pipeline.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/triangle.csh data/ui.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat + rm -f qstd/memory.o qstd/plat.o qstd/str.o qstd/pack.o cfg/cfgparse.o sc/sc.o sc/includer.o app.o asset.o c2.o camera.o debugdraw.o editor.o maths.o model.o pipeline.o scene.o ui.o video.o world.o convtexture.o convmodel.o convmaterial.o packer.o qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d maths.d model.d pipeline.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ui.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat rm -f shadercompiler rmdir data rm -f c2 diff --git a/c2.cpp b/c2.cpp index 28e63b5..e8e6c82 100644 --- a/c2.cpp +++ b/c2.cpp @@ -254,10 +254,10 @@ struct Sky { Fullscreen_Quad& quad, Render_Pass& pass, Sampler_Id sampler, - const Camera& cam + const Camera& cam, + Texture_Id target ) { - Texture_Id backbuffer_id = d->get_backbuffer(); - Texture& backbuffer = d->get_texture(backbuffer_id); + Texture& backbuffer = d->get_texture(target); Cbuffer* cb = (Cbuffer*)config.map(d); cb->iview = cam.get_view().inverse(); cb->iprojection = cam.get_proj().inverse(); @@ -554,6 +554,68 @@ struct Env_Probe { } }; +struct Tonemap { + Staged_Buffer config; + Shader* shader; + int config_binding, vert_binding, src_binding; + + struct Cbuffer { + float exposure; + }; + + void init(Device* d, Asset_Arena* assets) { + shader = (Shader*)assets->load("tonemap.csh"); + assert(shader != 0); + vert_binding = shader->binding_index("verts"); + assert(vert_binding >= 0); + src_binding = shader->descriptor_binding("src"); + assert(src_binding >= 0); + config_binding = shader->descriptor_binding("config"); + assert(config_binding >= 0); + config.init( + d, + "Tonemap Cbuffer", + sizeof(Cbuffer), + Buffer_Flags::constant_buffer + ); + } + + void destroy(Device* d) { + config.destroy(d); + } + + void update(Device* d, float exposure) { + Context& ctx = d->get_ctx(); + Cbuffer* b = (Cbuffer*)config.map(d); + b->exposure = exposure; + config.unmap(d); + config.update(ctx); + } + + void render( + Device* d, + Arena* a, + Fullscreen_Quad& quad, + Render_Pass& pass, + Texture_Id src, + Sampler_Id sampler + ) { + Context& ctx = d->get_ctx(); + Pipeline_Builder pb(a, d); + pb.begin(); + pb.shader(shader->id); + pb.vertex_format(shader->vf); + pb.texture( + src_binding, + src, + sampler + ); + pb.cbuffer(config_binding, config.gpuonly); + Pipeline& pip = pb.build(); + quad.render(ctx, pip, pass, vert_binding); + } +}; + struct Config_Buffer { float offset[2]; }; @@ -579,8 +641,10 @@ struct C2 : public App { Fullscreen_Quad quad; Sky sky; Env_Probe eprobe; + Tonemap tonemap; Buffer_Id vbo, cbuf; Sampler_Id clamped_linear; + Texture_Id hdr_target; Line_Renderer lr; World* world; UI* ui; @@ -618,6 +682,7 @@ struct C2 : public App { assets.init(&asset_arena, "pack", 128); dev = Device::create(&video_arena, this); default_texture = make_default_texture(dev); + make_hdr_target(); model_loader.init(dev, &assets); mat_loader.init(&assets, default_texture); register_asset_loader("MODL", &model_loader); @@ -650,6 +715,7 @@ struct C2 : public App { scene.init(&scene_arena, 32, clamped_linear); sky.init(dev, &assets); eprobe.init(dev, &assets, 256); + tonemap.init(dev, &assets); camera.init(); { monkey = world->create_entity(); @@ -694,7 +760,7 @@ struct C2 : public App { Pipeline_Builder pb(&frame_arena, dev); pb.begin_rp(); - pb.rp_target(dev->get_backbuffer(), { r, 0x00, 0xff, 0xff }); + pb.rp_target(hdr_target, { r, 0x00, 0xff, 0xff }); Render_Pass& pass = pb.build_rp(); pb.begin(); @@ -737,20 +803,24 @@ struct C2 : public App { Render_Pass& depth_prepass = pb.build_rp(); pb.begin_rp(); - pb.rp_target(dev->get_backbuffer(), Clear_Mode::restore); + pb.rp_target(hdr_target, Clear_Mode::restore); pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore); Render_Pass& pass2 = pb.build_rp(); pb.begin_rp(); - pb.rp_target(dev->get_backbuffer(), Clear_Mode::restore); + pb.rp_target(hdr_target, Clear_Mode::restore); pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore); Render_Pass& sky_pass = pb.build_rp(); + pb.begin_rp(); + pb.rp_target(dev->get_backbuffer(), Clear_Mode::discard); + Render_Pass& tonemap_pass = pb.build_rp(); + ctx.debug_push("environment cube"); eprobe.render(dev, &frame_arena, quad, sky); ctx.debug_pop(); - Texture& bb = dev->get_texture(dev->get_backbuffer()); + Texture& bb = dev->get_texture(hdr_target); world->get(monkey).mat = m4f::translate( m4f::identity(), v3f(0.0f, 0.0f, 0.0f) @@ -787,7 +857,21 @@ struct C2 : public App { quad, sky_pass, clamped_linear, - camera + camera, + hdr_target + ); + ctx.debug_pop(); + + tonemap.update(dev, 0.2f); + + ctx.debug_push("TONEMAP"); + tonemap.render( + dev, + &frame_arena, + quad, + tonemap_pass, + hdr_target, + clamped_linear ); ctx.debug_pop(); @@ -830,10 +914,12 @@ struct C2 : public App { sky.destroy(dev); lr.destroy(dev); eprobe.destroy(dev); + tonemap.destroy(dev); ui->destroy(); deinit_editor(); assets.destroy(); dev->destroy_texture(default_texture); + dev->destroy_texture(hdr_target); dev->destroy_sampler(clamped_linear); dev->destroy_buffer(vbo); dev->destroy_buffer(cbuf); @@ -843,6 +929,22 @@ struct C2 : public App { void on_resize() override { ui->layout(w, h); dev->on_resize(); + dev->destroy_texture(hdr_target); + make_hdr_target(); + } + + void make_hdr_target() { + hdr_target = dev->create_texture( + "HDR target", + texture_format_rgba16f, + Texture_Flags::sampleable | Texture_Flags::colour_target, + w, + h, + 1, + 1, + 1, + Buffer_Id(0) + ); } void on_text_input(const char* buf) override { diff --git a/configure.lua b/configure.lua index ac95b4d..3d4a748 100644 --- a/configure.lua +++ b/configure.lua @@ -45,6 +45,7 @@ config = { "sky", "surface", "surface_depthonly", + "tonemap", "triangle", "ui", }, diff --git a/intermediate/tonemap.glsl b/intermediate/tonemap.glsl new file mode 100644 index 0000000..5c41a6e --- /dev/null +++ b/intermediate/tonemap.glsl @@ -0,0 +1,85 @@ +#ifdef DESC +[program] +type: graphics +vertex: main +fragment: main + +[binding] +name: verts +rate: vertex +[attribute] +name: position +type: vec2 +[attribute] +name: uv +type: vec2 + +[interpolator] +name: uv +type: vec2 + +[struct] +name: Config +[variable] +name: exposure +type: float + +[cbuffer] +name: config +type: Config +stage: fragment + +[texture] +name: src +stage: fragment +dimension: 2 + +[target] +name: colour +type: vec4 +#endif + +#ifdef VERTEX_SHADER +void main() { + interpolator.uv = uv; + gl_Position = vec4(position, 1.0, 1.0); +} +#endif + +#ifdef FRAGMENT_SHADER + +vec3 to_srgb(vec3 lin) { + bvec3 cutoff = lessThan(lin, 0.0031308.xxx); + vec3 higher = 1.055.xxx * pow(lin, vec3(1.0 / 2.4)) - 0.055.xxx; + vec3 lower = lin.rgb * 12.92.xxx; + return mix(higher, lower, cutoff); +} + +vec3 aces(vec3 x) { + float a = 2.51; + float b = 0.03; + float c = 2.43; + float d = 0.59; + float e = 0.14; + return clamp( + (x * (a * x + b)) / (x * (c * x + d) + e), + 0.0, + 1.0f + ); +} + +vec3 hejl(vec3 x, float whitepoint) { + vec4 vh = vec4(x, whitepoint); + vec4 va = (1.425 * vh) + 0.05; + vec4 vf = ((vh * va + 0.004f) / ((vh * (va + 0.55f) + 0.0491f))) - 0.0821f; + return vf.rgb / vf.www; +} + +void main() { + vec2 uv = interpolator.uv; + vec3 lin = texture(src, uv).rgb * config.exposure; + lin = hejl(lin, 1.0); + colour = vec4(to_srgb(lin), 1.0); +} +#endif + diff --git a/todo.txt b/todo.txt index 984a251..5212343 100644 --- a/todo.txt +++ b/todo.txt @@ -18,6 +18,7 @@ todo list - [x] material system - [x] render a sky box - [x] PBR + IBL + - [x] Tonemapping - [ ] shadows - [ ] MSAA - [ ] GI -- cgit v1.2.3-54-g00ecf