diff options
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | build.ninja | 9 | ||||
-rw-r--r-- | c2.cpp | 71 | ||||
-rw-r--r-- | configure.lua | 1 | ||||
-rw-r--r-- | intermediate/surface.glsl | 59 | ||||
-rw-r--r-- | intermediate/ts.glsl | 148 | ||||
-rw-r--r-- | lighting.cpp | 49 | ||||
-rw-r--r-- | lighting.hpp | 6 | ||||
-rw-r--r-- | model.cpp | 2 | ||||
-rw-r--r-- | model.hpp | 1 | ||||
-rw-r--r-- | renderer.cpp | 180 | ||||
-rw-r--r-- | renderer.hpp | 36 | ||||
-rw-r--r-- | video.cpp | 2 |
13 files changed, 450 insertions, 131 deletions
@@ -118,15 +118,18 @@ data/tonemap.csh: intermediate/tonemap.glsl shadercompiler | data data/triangle.csh: intermediate/triangle.glsl shadercompiler | data cpp -MMD -MF data/triangle.d -MT data/triangle.csh -Iintermediate intermediate/triangle.glsl > /dev/null ./shadercompiler intermediate/triangle.glsl data/triangle.csh +data/ts.csh: intermediate/ts.glsl shadercompiler | data + cpp -MMD -MF data/ts.d -MT data/ts.csh -Iintermediate intermediate/ts.glsl > /dev/null + ./shadercompiler intermediate/ts.glsl data/ts.csh data/ui.csh: intermediate/ui.glsl shadercompiler | data cpp -MMD -MF data/ui.d -MT data/ui.csh -Iintermediate intermediate/ui.glsl > /dev/null ./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/tonemap.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/ts.csh data/ui.csh | data ./convmodel data intermediate/monkey.glb data/monkey.mdl -data/cube.mdl: convmodel intermediate/cube.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 +data/cube.mdl: convmodel intermediate/cube.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/ts.csh data/ui.csh | data ./convmodel data intermediate/cube.glb data/cube.mdl -data/scene.mdl: convmodel intermediate/scene.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 +data/scene.mdl: convmodel intermediate/scene.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/ts.csh data/ui.csh | data ./convmodel data intermediate/scene.glb data/scene.mdl data/22.tex: convtexture intermediate/22.bmp | data @@ -149,16 +152,16 @@ data/plastic.mat: convmaterial intermediate/plastic.mat | data data/greybox.mat: convmaterial intermediate/greybox.mat | data ./convmaterial intermediate/greybox.mat data/greybox.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/cube.mdl data/scene.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 data/greybox.mat - ./packer pack data debug.csh mip_spec.csh sky.csh surface.csh surface_depthonly.csh tonemap.csh triangle.csh ui.csh monkey.mdl cube.mdl scene.mdl 22.tex kita.tex brick_albedo.tex brick_ao.tex brick_normal.tex sky.tex bricks.mat plastic.mat greybox.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/ts.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.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 data/greybox.mat + ./packer pack data debug.csh mip_spec.csh sky.csh surface.csh surface_depthonly.csh tonemap.csh triangle.csh ts.csh ui.csh monkey.mdl cube.mdl scene.mdl 22.tex kita.tex brick_albedo.tex brick_ao.tex brick_normal.tex sky.tex bricks.mat plastic.mat greybox.mat data: mkdir -p 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 lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.d data/mip_spec.d data/sky.d data/surface.d data/surface_depthonly.d data/tonemap.d data/triangle.d data/ui.d +-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 lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.d data/mip_spec.d data/sky.d data/surface.d data/surface_depthonly.d data/tonemap.d data/triangle.d data/ts.d data/ui.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 lighting.o maths.o model.o physics.o pipeline.o renderer.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 lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.d data/mip_spec.d data/sky.d data/surface.d data/surface_depthonly.d data/tonemap.d data/triangle.d data/ui.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/cube.mdl data/scene.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 data/greybox.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 lighting.o maths.o model.o physics.o pipeline.o renderer.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 lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.d data/mip_spec.d data/sky.d data/surface.d data/surface_depthonly.d data/tonemap.d data/triangle.d data/ts.d data/ui.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/ts.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.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 data/greybox.mat rm -f shadercompiler rmdir data rm -f c2 diff --git a/build.ninja b/build.ninja index 0d15a5e..8635232 100644 --- a/build.ninja +++ b/build.ninja @@ -83,11 +83,12 @@ build data/surface.csh: shadercompiler intermediate/surface.glsl | shadercompile build data/surface_depthonly.csh: shadercompiler intermediate/surface_depthonly.glsl | shadercompiler.exe build data/tonemap.csh: shadercompiler intermediate/tonemap.glsl | shadercompiler.exe build data/triangle.csh: shadercompiler intermediate/triangle.glsl | shadercompiler.exe +build data/ts.csh: shadercompiler intermediate/ts.glsl | shadercompiler.exe build data/ui.csh: shadercompiler intermediate/ui.glsl | shadercompiler.exe -build data/monkey.mdl: convmodel intermediate/monkey.glb | convmodel.exe 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 -build data/cube.mdl: convmodel intermediate/cube.glb | convmodel.exe 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 -build data/scene.mdl: convmodel intermediate/scene.glb | convmodel.exe 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 +build data/monkey.mdl: convmodel intermediate/monkey.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh +build data/cube.mdl: convmodel intermediate/cube.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh +build data/scene.mdl: convmodel intermediate/scene.glb | convmodel.exe data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/tonemap.csh data/triangle.csh data/ts.csh data/ui.csh build data/bricks.mat: convmaterial intermediate/bricks.mat | convmaterial.exe build data/plastic.mat: convmaterial intermediate/plastic.mat | convmaterial.exe @@ -106,5 +107,5 @@ build data/brick_normal.tex: convtexture intermediate/brick_normal.bmp | convtex build data/sky.tex: convtexture intermediate/sky.hdr | convtexture.exe format = rgba16f -build 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/cube.mdl data/scene.mdl data/bricks.mat data/plastic.mat data/greybox.mat data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex | packer.exe +build 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/ts.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.mdl data/bricks.mat data/plastic.mat data/greybox.mat data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex | packer.exe @@ -162,61 +162,6 @@ struct Orbit_Cam { } }; -struct Fullscreen_Quad { - Buffer_Id vb; - - void init(Device* d) { - float verts[] = { - -1.0f, -1.0f, 0.0f, 0.0f, - -1.0f, 3.0f, 0.0f, 2.0f, - 3.0f, -1.0f, 2.0f, 0.0f - }; - Buffer_Id stage; - void* mem; - stage = d->create_buffer( - "sky vb stage", - sizeof verts, - Buffer_Flags::cpu_readwrite | - Buffer_Flags::copy_src - ); - mem = d->map_buffer(stage, 0, sizeof verts); - memcpy(mem, verts, sizeof verts); - d->unmap_buffer(stage); - vb = d->create_buffer( - "fullscreen quad", - sizeof verts, - Buffer_Flags::copy_dst | - Buffer_Flags::vertex_buffer - ); - Context& ctx = d->acquire(); - ctx.copy(vb, stage); - d->submit(ctx); - d->destroy_bufferi(stage); - } - - void destroy(Device* d) { - d->destroy_buffer(vb); - } - - void render( - Context& ctx, - Pipeline& pip, - Render_Pass& pass, - int bind - ) { - Vertex_Buffer_Binding vbb[] = {{ - .id = vb, - .offset = 0, - .target = bind - }, {}}; - Draw draw{}; - draw.verts = vbb; - draw.vertex_count = 3; - draw.instance_count = 1; - ctx.submit(draw, pip, pass); - } -}; - struct Sky { Staged_Buffer config; Texture_Id texture; @@ -647,7 +592,6 @@ struct C2 : public App { Lighting lighting; Camera_Id camera; Orbit_Cam orbit_cam; - Fullscreen_Quad quad; Sky sky; Env_Probe eprobe; Tonemap tonemap; @@ -703,7 +647,6 @@ struct C2 : public App { ui_shader = (Shader*)assets.load("ui.csh"); texture = (Texture*)assets.load("22.tex"); texture2 = (Texture*)assets.load("kita.tex"); - quad.init(dev); cbuf = dev->create_buffer( "config buffer", sizeof(Config_Buffer), @@ -715,7 +658,7 @@ struct C2 : public App { per_frame_memory_size ); clamped_linear = create_clamped_linear(dev); - renderer.init(arena, dev); + renderer.init(arena, dev, assets); world = (World*)arena_alloc(arena, sizeof *world); world->init(arena); ui = UI::create(this, &ui_arena); @@ -726,7 +669,7 @@ struct C2 : public App { ui->layout(w, h); fps_label = ui->create_element<UI::Label>(ui->root, ""); scene.init(&scene_arena, 32, clamped_linear); - lighting.init(dev); + lighting.init(dev, w, h); sky.init(dev, &assets); eprobe.init(dev, &assets, 256); tonemap.init(dev, &assets); @@ -884,7 +827,7 @@ struct C2 : public App { Render_Pass& tonemap_pass = pb.build_rp(); ctx.debug_push("environment cube"); - eprobe.render(dev, &frame_arena, quad, sky); + eprobe.render(dev, &frame_arena, renderer.quad, sky); ctx.debug_pop(); renderer.env_cubemap = eprobe.get_cubemap(); @@ -911,7 +854,7 @@ struct C2 : public App { sky.render( dev, &frame_arena, - quad, + renderer.quad, sky_pass, clamped_linear, pcam, @@ -925,7 +868,7 @@ struct C2 : public App { tonemap.render( dev, &frame_arena, - quad, + renderer.quad, tonemap_pass, hdr_target, clamped_linear @@ -959,7 +902,7 @@ struct C2 : public App { clamped_linear ); Pipeline& ui_pip = pb.build(); - quad.render( + renderer.quad.render( ctx, ui_pip, ui_pass, @@ -1001,7 +944,6 @@ struct C2 : public App { } void on_destroy() override { - quad.destroy(dev); scene.destroy(dev); sky.destroy(dev); lighting.destroy(dev, renderer); @@ -1030,6 +972,7 @@ struct C2 : public App { dev->destroy_buffer(ui_buffer); make_hdr_target(); make_ui_texture(); + lighting.recreate(dev, w, h); } void make_hdr_target() { diff --git a/configure.lua b/configure.lua index 9bfe342..d944308 100644 --- a/configure.lua +++ b/configure.lua @@ -50,6 +50,7 @@ config = { "surface_depthonly", "tonemap", "triangle", + "ts", "ui", }, materials = { diff --git a/intermediate/surface.glsl b/intermediate/surface.glsl index 71a4307..82bf2f6 100644 --- a/intermediate/surface.glsl +++ b/intermediate/surface.glsl @@ -29,6 +29,9 @@ type: vec2 name: uv type: vec2 [interpolator] +name: screen +type: vec4 +[interpolator] name: position type: vec4 [interpolator] @@ -114,7 +117,7 @@ dimension: cube [texture] name: shadowmaps stage: fragment -dimension: shadowArray +dimension: array [target] name: colour @@ -133,7 +136,9 @@ void main() { interpolator.uv = uv; interpolator.position = pos; interpolator.tbn = mat3(t, b, n); - gl_Position = c_vp.view_projection * pos; + pos = c_vp.view_projection * pos; + interpolator.screen = pos; + gl_Position = pos; } #endif @@ -170,54 +175,10 @@ float specular_brdf(vec2 uv, vec3 ref, vec3 l, vec3 v, vec3 n) { return (D * F * G) / (4.0 * ndl * ndv + 0.001); } -vec2 poissonDisk[16] = vec2[]( - vec2(-0.94201624, -0.39906216), - vec2(0.94558609, -0.76890725), - vec2(-0.094184101, -0.92938870), - vec2(0.34495938, 0.29387760), - vec2(-0.91588581, 0.45771432), - vec2(-0.81544232, -0.87912464), - vec2(-0.38277543, 0.27676845), - vec2(0.97484398, 0.75648379), - vec2(0.44323325, -0.97511554), - vec2(0.53742981, -0.47373420), - vec2(-0.26496911, -0.41893023), - vec2(0.79197514, 0.19090188), - vec2(-0.24188840, 0.99706507), - vec2(-0.81409955, 0.91437590), - vec2(0.19984126, 0.78641367), - vec2(0.14383161, -0.14100790) -); - -float random(vec3 seed, int i){ - vec4 seed4 = vec4(seed,i); - float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673)); - return fract(sin(dot_product) * 43758.5453); -} - -float get_shadow(Light l, vec3 wpos) { - const int taps = 4; - const float w = 1.0 / float(taps); - const float m = 1.0 / 1000.0; - int i; - float d = 0.0f; - Caster caster = casters[l.caster_id]; - vec4 surf = caster.projection * vec4(wpos, 1.0); - surf /= surf.w; - surf.xy = surf.xy * 0.5 + 0.5; - surf.z -= 0.005; - for (i = 0; i < taps; i++) { - int index = int(16.0 * random(floor(wpos.xyz * 1000.0), i)) % 16; - vec2 coord = surf.xy + poissonDisk[index] * m; - vec4 vec = vec4(coord, float(l.caster_id), surf.z); - d += texture(shadowmaps, vec).r * w; - } - return d; -} - void main() { int i; vec2 uv = interpolator.uv; + vec2 suv = (interpolator.screen.xy / interpolator.screen.w) * 0.5 + 0.5; vec3 p = interpolator.position.xyz; vec3 nrmsample = texture(normal, uv).rgb; @@ -251,9 +212,7 @@ void main() { spec_col * specular_brdf(uv, ref, light_dir, view_dir, nrm) * cos_theta_i; - float shadow = 1.0f; - if (l.caster_id >= 0) - shadow = get_shadow(l, p); + float shadow = texture(shadowmaps, vec3(suv, float(l.caster_id))).r; light += (diffuse + spec) * l.brightness * l.colour * shadow; } diff --git a/intermediate/ts.glsl b/intermediate/ts.glsl new file mode 100644 index 0000000..23195f6 --- /dev/null +++ b/intermediate/ts.glsl @@ -0,0 +1,148 @@ +#ifdef DESC +[program] +type: graphics +vertex: main +fragment: main +#endif + +#include "forward.h" + +#ifdef DESC + +[binding] +name: verts +rate: vertex +[attribute] +name: position +type: vec2 +[attribute] +name: uv +type: vec2 + +[interpolator] +name: uv +type: vec2 + +[texture] +name: shadowmaps +stage: fragment +dimension: shadowArray +[texture] +name: previous +stage: fragment +dimension: 2 +[texture] +name: depthmap +stage: fragment +dimension: 2 + +[struct] +name: Config +[variable] +name: inv_view +type: mat4 +[variable] +name: inv_proj +type: mat4 +[variable] +name: prev_vp +type: mat4 + +[struct] +name: Caster_Config +[variable] +name: index +type: int + +[cbuffer] +name: config +type: Config +stage: fragment + +[cbuffer] +name: caster_config +type: Caster_Config +stage: fragment + +[sbuffer] +name: casters +type: Caster +stage: fragment + +[target] +name: shadow_amount +type: float + +#endif + +#ifdef VERTEX_SHADER +void main() { + interpolator.uv = uv; + gl_Position = vec4(position, 1.0, 1.0); +} +#endif + +#ifdef FRAGMENT_SHADER + +vec2 poissonDisk[16] = vec2[]( + vec2(-0.94201624, -0.39906216), + vec2(0.94558609, -0.76890725), + vec2(-0.094184101, -0.92938870), + vec2(0.34495938, 0.29387760), + vec2(-0.91588581, 0.45771432), + vec2(-0.81544232, -0.87912464), + vec2(-0.38277543, 0.27676845), + vec2(0.97484398, 0.75648379), + vec2(0.44323325, -0.97511554), + vec2(0.53742981, -0.47373420), + vec2(-0.26496911, -0.41893023), + vec2(0.79197514, 0.19090188), + vec2(-0.24188840, 0.99706507), + vec2(-0.81409955, 0.91437590), + vec2(0.19984126, 0.78641367), + vec2(0.14383161, -0.14100790) +); + +float random(vec3 seed, int i){ + vec4 seed4 = vec4(seed,i); + float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673)); + return fract(sin(dot_product) * 43758.5453); +} + +float get_shadow(int id, vec3 wpos) { + const int taps = 4; + const float w = 1.0 / float(taps); + const float m = 1.0 / 1000.0; + int i; + float d = 0.0f; + Caster caster = casters[id]; + vec4 surf = caster.projection * vec4(wpos, 1.0); + surf /= surf.w; + surf.xy = surf.xy * 0.5 + 0.5; + surf.z -= 0.005; + for (i = 0; i < taps; i++) { + int index = int(16.0 * random(floor(wpos.xyz * 1000.0), i + globals.frame)) % 16; + vec2 coord = surf.xy + poissonDisk[index] * m; + vec4 vec = vec4(coord, float(id), surf.z); + d += texture(shadowmaps, vec).r * w; + } + return d; +} + +vec3 get_world_pos(float depth, vec2 uv) { + float z = depth; + vec4 clip = vec4(uv * 2.0 - 1.0, z, 1.0); + vec4 view = config.inv_proj * clip; + view /= view.w; + return (config.inv_view * view).xyz; +} + +void main() { + vec2 uv = interpolator.uv; + float d = texture(depthmap, uv).r; + vec3 wpos = get_world_pos(d, uv); + float prev = texture(previous, uv).r; + float current = get_shadow(caster_config.index, wpos); + shadow_amount = (prev + current) * 0.5; +} +#endif diff --git a/lighting.cpp b/lighting.cpp index 0e41ddd..4f1fdfb 100644 --- a/lighting.cpp +++ b/lighting.cpp @@ -20,7 +20,7 @@ struct GPU_Caster { m4f projection; }; -void Lighting::init(Device* dev) { +void Lighting::init(Device* dev, int w, int h) { int i; Sampler_State ss{}; lights.init( @@ -46,6 +46,9 @@ void Lighting::init(Device* dev) { max_shadows, 0 ); + zero(ss_shadows, sizeof ss_shadows); + zero(ss_shadow_slices, sizeof ss_shadow_slices); + recreate(dev, w, h); for (i = 0; i < max_shadows; i++) { cameras[i] = 0; shadow_slices[i] = dev->alias_texture( @@ -85,6 +88,50 @@ void Lighting::destroy(Device* dev, Renderer& r) { r.destroy_camera(cameras[i]); } dev->destroy_texture(shadows); + destroy_ss(dev); +} + +void Lighting::destroy_ss(Device* dev) { + int i, j; + for (i = 0; i < 2; i++) { + for (j = 0; j < max_shadows; j++) + if (ss_shadow_slices[i][j]) + dev->destroy_texture(ss_shadow_slices[i][j]); + if (ss_shadows[i]) + dev->destroy_texture(ss_shadows[i]); + } +} + +void Lighting::recreate(Device* dev, int w, int h) { + int i, j; + destroy_ss(dev); + for (i = 0; i < 2; i++) { + ss_shadows[i] = dev->create_texture( + "Shadow accumulation buffer", + texture_format_r8i, + Texture_Flags::sampleable | Texture_Flags::colour_target, + w, + h, + 1, + 1, + max_shadows, + 0 + ); + for (j = 0; j < max_shadows; j++) + ss_shadow_slices[i][j] = dev->alias_texture( + ss_shadows[i], + "Shadow accumulation buffer slice", + texture_format_r8i, + Texture_Flags::colour_target, + shadow_res, + shadow_res, + 1, + 1, + 1, + 0, + j + ); + } } void Lighting::write_bufs( diff --git a/lighting.hpp b/lighting.hpp index ccd08d3..0d331d7 100644 --- a/lighting.hpp +++ b/lighting.hpp @@ -19,10 +19,14 @@ struct Lighting { Staged_Buffer casters; Texture_Id shadows; Texture_Id shadow_slices[max_shadows]; + Texture_Id ss_shadows[2]; + Texture_Id ss_shadow_slices[2][max_shadows]; Sampler_Id shadow_sampler; Camera_Id cameras[max_shadows]; int light_count, caster_count; - void init(Device* dev); + void init(Device* dev, int w, int h); + void destroy_ss(Device* dev); + void recreate(Device* dev, int w, int h); void destroy(Device* dev, Renderer& r); void update( Device* dev, @@ -388,7 +388,7 @@ void Model_Instance::render( pb.shader(mesh.shader); pb.sbuffer(mesh.light_binding, lighting->lights.gpuonly); pb.sbuffer(mesh.casters_binding, lighting->casters.gpuonly); - pb.texture(mesh.shadowmaps_binding, lighting->shadows, lighting->shadow_sampler); + pb.texture(mesh.shadowmaps_binding, res.shadows, res.sampler); mesh.material->use(pb, res.sampler, dev->get_shader(mesh.shader)); pb.cbuffer( mesh.mat_binding, @@ -97,6 +97,7 @@ struct Material_Loader : public Asset_Loader { struct Model_Resources { Texture_Id env_cubemap; + Texture_Id shadows; Sampler_Id sampler; Buffer_Id vp; Buffer_Id globals; diff --git a/renderer.cpp b/renderer.cpp index d8c4895..ffc0a3c 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -5,10 +5,23 @@ extern "C" { #include "memory.h" } +#include <string.h> + struct VP_Cbuffer { m4f view_projection; }; +struct TS_Cbuffer { + m4f inv_view; + m4f inv_proj; + m4f prev_vp; +}; + +struct TS_Caster_Config { + int index; + char pad[60]; +}; + struct Global_Cbuffer { v3f camera_pos; int light_count; @@ -36,7 +49,22 @@ void init_drawlist( ); } -void Renderer::init(Arena* arena, Device* d) { +void Renderer::make_ts_sampler(Device* d) { + Sampler_State s{}; + s.min = Filter_Mode::point; + s.mag = Filter_Mode::point; + s.mip = Filter_Mode::point; + s.address_u = Address_Mode::border; + s.address_v = Address_Mode::border; + s.border[0] = 0.0f; + ts_sampler = d->create_sampler("temporal shadow sampler", s); +} + +void Renderer::init( + Arena* arena, + Device* d, + Asset_Arena& assets +) { int i; auto id = [&](int did, int cap) { init_drawlist(&drawlists[did], d, arena, cap); @@ -52,6 +80,37 @@ void Renderer::init(Arena* arena, Device* d) { sizeof(Global_Cbuffer), Buffer_Flags::constant_buffer ); + ts_config.init( + d, + "Temporal shadow cbuffer", + sizeof(TS_Cbuffer), + Buffer_Flags::constant_buffer + ); + ts_config2.init( + d, + "Temporal shadow casters", + sizeof(TS_Caster_Config) * Lighting::max_shadows, + Buffer_Flags::constant_buffer + ); + quad.init(d); + ts_shader = (Shader*)assets.load("ts.csh"); + ts_shadowmap_binding = ts_shader->descriptor_binding("shadowmaps"); + ts_depthmap_binding = ts_shader->descriptor_binding("depthmap"); + ts_prev_binding = ts_shader->descriptor_binding("previous"); + ts_vert_binding = ts_shader->binding_index("verts"); + ts_config_binding = ts_shader->descriptor_binding("config"); + ts_caster_config_binding = ts_shader->descriptor_binding("caster_config"); + ts_casters_binding = ts_shader->descriptor_binding("casters"); + ts_globals_binding = ts_shader->descriptor_binding("globals"); + assert(ts_shadowmap_binding >= 0); + assert(ts_depthmap_binding >= 0); + assert(ts_prev_binding >= 0); + assert(ts_vert_binding >= 0); + assert(ts_config_binding >= 0); + assert(ts_caster_config_binding >= 0); + assert(ts_casters_binding >= 0); + assert(ts_globals_binding >= 0); + make_ts_sampler(d); frame = 0; } @@ -60,6 +119,10 @@ void Renderer::destroy(Device* d) { for (i = 0; i < drawlist_count; i++) drawlists[i].vp.destroy(d); globals.destroy(d); + ts_config.destroy(d); + ts_config2.destroy(d); + quad.destroy(d); + d->destroy_sampler(ts_sampler); } void Renderer::set_camera(Camera_Id cam, int drawlist) { @@ -81,6 +144,7 @@ void Drawlist::render( vpc->view_projection = cam.get_proj() * cam.get_view(); vp.unmap(dev); vp.update(dev->get_ctx()); + res.shadows = l->ss_shadows[r.frame & 1]; res.sampler = r.clamped_linear; res.env_cubemap = r.env_cubemap; res.vp = vp.gpuonly; @@ -106,6 +170,67 @@ void Renderer::update_globals( globals.update(ctx); } +void Renderer::temporal_shadows( + Device* dev, + Context& ctx, + const Lighting* l, + Pipeline_Builder& pb +) { + int i, c = l->caster_count; + Camera& cam = get_camera(drawlists[FORWARD].camera); + TS_Cbuffer* cbuf = (TS_Cbuffer*)ts_config.map(dev); + TS_Caster_Config* casters = (TS_Caster_Config*)ts_config.map(dev); + for (i = 0; i < c; i++) { + casters[i].index = i; + } + cbuf->inv_view = cam.get_view().inverse(); + cbuf->inv_proj = cam.get_proj().inverse(); + ts_config.unmap(dev); + ts_config2.unmap(dev); + ctx.debug_push("temporal shadows"); + ts_config.update(ctx); + ts_config2.update(ctx); + for (i = 0; i < c; i++) { + int ind = frame & 1; + auto& pass = pb + .begin_rp() + .rp_target(l->ss_shadow_slices[ind][i], Clear_Mode::discard) + .build_rp(); + auto& pip = pb + .begin() + .shader(ts_shader->id) + .vertex_format(ts_shader->vf) + .texture( + ts_shadowmap_binding, + l->shadows, + l->shadow_sampler) + .texture( + ts_prev_binding, + l->ss_shadow_slices[!ind][i], + ts_sampler) + .texture( + ts_depthmap_binding, + dev->get_depth_target(), + ts_sampler) + .cbuffer(ts_config_binding, ts_config.gpuonly) + .cbuffer( + ts_caster_config_binding, + ts_config2.gpuonly, + i * sizeof(TS_Caster_Config), + sizeof(TS_Caster_Config)) + .cbuffer(ts_globals_binding, globals.gpuonly) + .sbuffer(ts_casters_binding, l->casters.gpuonly) + .build(); + quad.render( + ctx, + pip, + pass, + ts_vert_binding + ); + } + ctx.debug_pop(); +} + void Renderer::render( Device* dev, Arena* a, Texture_Id hdr_target, @@ -154,6 +279,8 @@ void Renderer::render( } ctx.debug_pop(); + temporal_shadows(dev, ctx, l, pb); + ctx.debug_push("forward"); drawlists[FORWARD].render(*this, dev, a, l, forward_pass, 0); ctx.debug_pop(); @@ -210,3 +337,54 @@ void Renderer::setcam(int did, Camera_Id cam) { assert(cam.index); drawlists[did].camera = cam; } + +void Fullscreen_Quad::init(Device* d) { + float verts[] = { + -1.0f, -1.0f, 0.0f, 0.0f, + -1.0f, 3.0f, 0.0f, 2.0f, + 3.0f, -1.0f, 2.0f, 0.0f + }; + Buffer_Id stage; + void* mem; + stage = d->create_buffer( + "sky vb stage", + sizeof verts, + Buffer_Flags::cpu_readwrite | + Buffer_Flags::copy_src + ); + mem = d->map_buffer(stage, 0, sizeof verts); + memcpy(mem, verts, sizeof verts); + d->unmap_buffer(stage); + vb = d->create_buffer( + "fullscreen quad", + sizeof verts, + Buffer_Flags::copy_dst | + Buffer_Flags::vertex_buffer + ); + Context& ctx = d->acquire(); + ctx.copy(vb, stage); + d->submit(ctx); + d->destroy_bufferi(stage); +} + +void Fullscreen_Quad::destroy(Device* d) { + d->destroy_buffer(vb); +} + +void Fullscreen_Quad::render( + Context& ctx, + Pipeline& pip, + Render_Pass& pass, + int bind +) { + Vertex_Buffer_Binding vbb[] = {{ + .id = vb, + .offset = 0, + .target = bind + }, {}}; + Draw draw{}; + draw.verts = vbb; + draw.vertex_count = 3; + draw.instance_count = 1; + ctx.submit(draw, pip, pass); +} diff --git a/renderer.hpp b/renderer.hpp index c49c804..46f5331 100644 --- a/renderer.hpp +++ b/renderer.hpp @@ -12,6 +12,7 @@ enum { SHADOW_MAP_END = SHADOW_MAP_START + Lighting::max_shadows, drawlist_count = SHADOW_MAP_END }; +struct Asset_Arena; struct Model_Instance; struct Renderer; @@ -32,26 +33,59 @@ struct Drawlist { ); }; +struct Fullscreen_Quad { + Buffer_Id vb; + + void init(Device* d); + void destroy(Device* d); + void render( + Context& ctx, + Pipeline& pip, + Render_Pass& pass, + int bind + ); +}; + struct Renderer { static constexpr int max_cameras = 16; Hash_Map<Camera_Id, Camera, max_cameras> cameras; Drawlist drawlists[drawlist_count]; Staged_Buffer globals; + Fullscreen_Quad quad; int camera_count; int frame; + Shader* ts_shader; + int ts_shadowmap_binding; + int ts_depthmap_binding; + int ts_prev_binding; + int ts_vert_binding; + int ts_config_binding; + int ts_caster_config_binding; + int ts_casters_binding; + int ts_globals_binding; + Sampler_Id ts_sampler; + Staged_Buffer ts_config, ts_config2; + Sampler_Id clamped_linear; Texture_Id env_cubemap; - void init(Arena* arena, Device* d); + void init(Arena* arena, Device* d, Asset_Arena& assets); void destroy(Device* d); void set_camera(Camera_Id cam, int drawlist); + void make_ts_sampler(Device* d); void render( Device* dev, Arena* a, Texture_Id hdr_target, const Lighting* l ); + void temporal_shadows( + Device* dev, + Context& ctx, + const Lighting* l, + Pipeline_Builder& pb + ); void add_model(int drawlist, Model_Instance* m); void rem_model(int drawlist, Model_Instance* m); @@ -1386,7 +1386,7 @@ void Device_Vk::create_depth(int w, int h) { destroy_texture(depth); depth = create_texture( "default depth", - texture_format_d24s8, + texture_format_d32, Texture_Flags::sampleable | Texture_Flags::depth_stencil_target, w, h, |