From 528c5a7ef9e3e7cadf9a2caefa3ca115b382df75 Mon Sep 17 00:00:00 2001 From: quou Date: Sun, 2 Mar 2025 17:28:07 +1100 Subject: シ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c2.cpp | 1 - intermediate/forward.h | 6 ++++ intermediate/ts.glsl | 54 +++++++++++++++++++++++----------- lighting.cpp | 78 ++++++++++++++++++++++++++++++++++++------------- lighting.hpp | 21 +++++++++---- model.cpp | 4 +-- renderer.cpp | 47 +++++++++++++++++------------ renderer.hpp | 5 +++- sc/sc.cpp | 2 +- src/guy.blend | Bin 0 -> 483196 bytes video.cpp | 17 ++++++----- video.hpp | 1 + 12 files changed, 162 insertions(+), 74 deletions(-) create mode 100644 src/guy.blend diff --git a/c2.cpp b/c2.cpp index 3a14ea5..f53d59d 100644 --- a/c2.cpp +++ b/c2.cpp @@ -841,7 +841,6 @@ struct C2 : public App { pcam.update(); lighting.update(dev, ctx, *world, renderer, scene); update_scene(scene, dev, *world); - lr.add_box(scene.bound); ctx.debug_push("scene"); renderer.render( dev, diff --git a/intermediate/forward.h b/intermediate/forward.h index 7c4c9d3..156a185 100644 --- a/intermediate/forward.h +++ b/intermediate/forward.h @@ -22,6 +22,9 @@ name: Caster [variable] name: projection type: mat4 +[variable] +name: jittered +type: mat4 [struct] name: Globals @@ -41,4 +44,7 @@ type: Globals stage: fragment #endif + +#define max_casters 16 + #endif diff --git a/intermediate/ts.glsl b/intermediate/ts.glsl index 61dd728..d80d6e4 100644 --- a/intermediate/ts.glsl +++ b/intermediate/ts.glsl @@ -35,6 +35,10 @@ dimension: 2 name: depthmap stage: fragment dimension: 2 +[texture] +name: prev_occlusion +stage: fragment +dimension: 2 [struct] name: Config @@ -72,6 +76,9 @@ stage: fragment [target] name: shadow_amount type: float +[target] +name: occlusion +type: float #endif @@ -103,25 +110,25 @@ vec2 poissonDisk[16] = vec2[]( vec2(0.14383161, -0.14100790) ); -float random(vec3 seed, int i){ - vec4 seed4 = vec4(seed,i); +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) { +float get_shadow(int id, mat4 proj, 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); + vec4 surf = proj * 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; + float r = random(floor(wpos.xyz * 1000.0), i + globals.frame); + int index = int(16.0 * r) % 16; vec2 coord = surf.xy + poissonDisk[index] * m; vec4 vec = vec4(coord, float(id), surf.z); d += texture(shadowmaps, vec).r * w; @@ -129,31 +136,44 @@ float get_shadow(int id, vec3 wpos) { return d; } -vec3 get_world_pos(float depth, vec2 uv) { +vec4 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; + return config.inv_view * view; } void main() { - float w_prev = 0.9; - float w_cur = 0.1; + float w_prev = 0.99; + float w_cur = 0.01; + Caster caster = casters[caster_config.index]; vec2 uv = interpolator.uv; float d = texture(depthmap, uv).r; - vec3 wpos = get_world_pos(d, uv); - vec4 prev_pos = config.prev_vp * vec4(wpos, 1.0); + float o = texture(prev_occlusion, uv).r; + vec4 wpos = get_world_pos(d, uv); + vec4 prev_pos = config.prev_vp * vec4(wpos.xyz, 1.0); vec2 prev_uv = (prev_pos.xy / prev_pos.w) * 0.5 + 0.5; float prev = texture(previous, prev_uv).r; - float current = get_shadow(caster_config.index, wpos); + float base = get_shadow( + caster_config.index, + caster.projection, + wpos.xyz + ); + float jittered = get_shadow( + caster_config.index + max_casters, + caster.jittered, + wpos.xyz + ); if ( prev_uv.x < 0.0 || prev_uv.x > 1.0 || - prev_uv.y < 0.0 || prev_uv.y > 1.0 + prev_uv.y < 0.0 || prev_uv.y > 1.0 || + abs(d - o) > 0.001 ) { - w_prev = 0.0; - w_cur = 1.0; + shadow_amount = base; + } else { + shadow_amount = prev * w_prev + jittered * w_cur; } - shadow_amount = (prev * w_prev + current * w_cur); + occlusion = d; } #endif diff --git a/lighting.cpp b/lighting.cpp index 1eb4298..9f154cb 100644 --- a/lighting.cpp +++ b/lighting.cpp @@ -8,6 +8,8 @@ extern "C" { #include "plat.h" } +#include + /* needs to match surface shader */ struct GPU_Light { v3f dir; @@ -18,18 +20,19 @@ struct GPU_Light { struct GPU_Caster { m4f projection; + m4f jittered; }; void Lighting::init(Device* dev, int w, int h) { int i; Sampler_State ss{}; - lights.init( + gpu_lights.init( dev, "Light buffer", max_lights * sizeof(GPU_Light), Buffer_Flags::storage_buffer ); - casters.init( + gpu_casters.init( dev, "Caster buffer", max_shadows * sizeof(GPU_Caster), @@ -43,13 +46,14 @@ void Lighting::init(Device* dev, int w, int h) { shadow_res, 1, 1, - max_shadows, + shadowmap_count, 0 ); zero(ss_shadows, sizeof ss_shadows); zero(ss_shadow_slices, sizeof ss_shadow_slices); + zero(occlusion, sizeof occlusion); recreate(dev, w, h); - for (i = 0; i < max_shadows; i++) { + for (i = 0; i < shadowmap_count; i++) { cameras[i] = 0; shadow_slices[i] = dev->alias_texture( shadows, @@ -80,10 +84,10 @@ void Lighting::init(Device* dev, int w, int h) { void Lighting::destroy(Device* dev, Renderer& r) { int i; - lights.destroy(dev); - casters.destroy(dev); + gpu_lights.destroy(dev); + gpu_casters.destroy(dev); dev->destroy_sampler(shadow_sampler); - for (i = 0; i < max_shadows; i++) { + for (i = 0; i < shadowmap_count; i++) { dev->destroy_texture(shadow_slices[i]); r.destroy_camera(cameras[i]); } @@ -99,6 +103,8 @@ void Lighting::destroy_ss(Device* dev) { dev->destroy_texture(ss_shadow_slices[i][j]); if (ss_shadows[i]) dev->destroy_texture(ss_shadows[i]); + if (occlusion[i]) + dev->destroy_texture(occlusion[i]); } } @@ -131,7 +137,28 @@ void Lighting::recreate(Device* dev, int w, int h) { 0, j ); + occlusion[i] = dev->create_texture( + "Occlusion buffer", + texture_format_r32f, + Texture_Flags::sampleable | Texture_Flags::colour_target, + w, + h, + 1, + 1, + 1, + 0 + ); + } +} + +Camera_Id Lighting::gm_cam(Renderer& r) { + int id = cam_count++; + Camera_Id cid = cameras[id]; + if (!cid) { + cid = r.create_camera(); + cameras[id] = cid; } + return cid; } void Lighting::write_bufs( @@ -144,6 +171,10 @@ void Lighting::write_bufs( GPU_Light* ldst = (GPU_Light*)lptr; GPU_Caster* cdst = (GPU_Caster*)cptr; int count = 0, ccount = 0; + cam_count = 0; + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_real_distribution dist6(-0.01f, 0.01f); for (auto v : w.view()) { GPU_Light gl; Sun_Light& l = v.get(); @@ -155,15 +186,22 @@ void Lighting::write_bufs( gl.colour = l.colour; gl.dir = l.dir; if (l.caster && ccount < max_shadows) { + Camera* cam[2]; int cid = ccount++; - GPU_Caster& c = cdst[cid]; - Camera_Id camid = cameras[cid]; - if (!camid) - camid = r.create_camera(); - Camera& cam = r.get_camera(camid); - cam.init_shadow(l.dir, s.bound.min, s.bound.max); - c.projection = cam.get_proj() * cam.get_view(); - cameras[cid] = camid; + Caster& caster = casters[cid]; + GPU_Caster& gc = cdst[cid]; + v3f jitter( + dist6(rng), + dist6(rng), + dist6(rng) + ); + caster = Caster { gm_cam(r), gm_cam(r) }; + cam[0] = &r.get_camera(caster.reality); + cam[1] = &r.get_camera(caster.jittered); + cam[0]->init_shadow(l.dir, s.bound.min, s.bound.max); + cam[1]->init_shadow(l.dir + jitter, s.bound.min, s.bound.max); + gc.projection = cam[0]->get_proj() * cam[0]->get_view(); + gc.jittered = cam[1]->get_proj() * cam[1]->get_view(); gl.caster_id = cid; } else gl.caster_id = -1; @@ -181,10 +219,10 @@ void Lighting::update( Model_Scene& s ) { light_count = 0; - write_bufs(lights.map(dev), casters.map(dev), w, r, s); - casters.unmap(dev); - lights.unmap(dev); - lights.update(ctx); - casters.update(ctx); + write_bufs(gpu_lights.map(dev), gpu_casters.map(dev), w, r, s); + gpu_casters.unmap(dev); + gpu_lights.unmap(dev); + gpu_lights.update(ctx); + gpu_casters.update(ctx); } diff --git a/lighting.hpp b/lighting.hpp index 0d331d7..ac2d2c5 100644 --- a/lighting.hpp +++ b/lighting.hpp @@ -11,23 +11,32 @@ struct Model_Scene; struct Renderer; struct World; +struct Caster { + Camera_Id reality; + Camera_Id jittered; +}; + struct Lighting { static constexpr int max_lights = 128; static constexpr int max_shadows = 16; + static constexpr int shadowmap_count = max_shadows * 2; static constexpr int shadow_res = 2048; - Staged_Buffer lights; - Staged_Buffer casters; + Staged_Buffer gpu_lights; + Staged_Buffer gpu_casters; Texture_Id shadows; - Texture_Id shadow_slices[max_shadows]; + Texture_Id shadow_slices[shadowmap_count]; Texture_Id ss_shadows[2]; - Texture_Id ss_shadow_slices[2][max_shadows]; + Texture_Id ss_shadow_slices[2][shadowmap_count]; + Texture_Id occlusion[2]; Sampler_Id shadow_sampler; - Camera_Id cameras[max_shadows]; - int light_count, caster_count; + Caster casters[max_shadows]; + Camera_Id cameras[shadowmap_count]; + int light_count, caster_count, cam_count; 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); + Camera_Id gm_cam(Renderer& r); void update( Device* dev, Context& ctx, diff --git a/model.cpp b/model.cpp index 5806655..aa65898 100644 --- a/model.cpp +++ b/model.cpp @@ -386,8 +386,8 @@ void Model_Instance::render( } else { pb.depth(true, false, Depth_Mode::equal); pb.shader(mesh.shader); - pb.sbuffer(mesh.light_binding, lighting->lights.gpuonly); - pb.sbuffer(mesh.casters_binding, lighting->casters.gpuonly); + pb.sbuffer(mesh.light_binding, lighting->gpu_lights.gpuonly); + pb.sbuffer(mesh.casters_binding, lighting->gpu_casters.gpuonly); pb.texture(mesh.shadowmaps_binding, res.shadows, res.sampler); mesh.material->use(pb, res.sampler, dev->get_shader(mesh.shader)); pb.cbuffer( diff --git a/renderer.cpp b/renderer.cpp index a9d590a..8bc2d94 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -71,6 +71,8 @@ void Renderer::init( id(FORWARD, 512); for (i = SHADOW_MAP_START; i < SHADOW_MAP_END; i++) id(i, 512); + for (i = SHADOW_JIT_START; i < SHADOW_JIT_END; i++) + id(i, 512); camera_count = 1; cameras.init(); globals.init( @@ -101,6 +103,7 @@ void Renderer::init( 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"); + ts_prev_occlusion_binding = ts_shader->descriptor_binding("prev_occlusion"); assert(ts_shadowmap_binding >= 0); assert(ts_depthmap_binding >= 0); assert(ts_prev_binding >= 0); @@ -109,6 +112,7 @@ void Renderer::init( assert(ts_caster_config_binding >= 0); assert(ts_casters_binding >= 0); assert(ts_globals_binding >= 0); + assert(ts_prev_occlusion_binding >= 0); make_ts_sampler(d); frame = 0; } @@ -178,7 +182,7 @@ void Renderer::temporal_shadows( 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); + TS_Caster_Config* casters = (TS_Caster_Config*)ts_config2.map(dev); for (i = 0; i < c; i++) { casters[i].index = i; } @@ -195,6 +199,7 @@ void Renderer::temporal_shadows( auto& pass = pb .begin_rp() .rp_target(l->ss_shadow_slices[ind][i], Clear_Mode::discard) + .rp_target(l->occlusion[ind], Clear_Mode::discard) .build_rp(); auto& pip = pb .begin() @@ -212,6 +217,10 @@ void Renderer::temporal_shadows( ts_depthmap_binding, dev->get_depth_target(), ts_sampler) + .texture( + ts_prev_occlusion_binding, + l->occlusion[!ind], + ts_sampler) .cbuffer(ts_config_binding, ts_config.gpuonly) .cbuffer( ts_caster_config_binding, @@ -219,7 +228,7 @@ void Renderer::temporal_shadows( i * sizeof(TS_Caster_Config), sizeof(TS_Caster_Config)) .cbuffer(ts_globals_binding, globals.gpuonly) - .sbuffer(ts_casters_binding, l->casters.gpuonly) + .sbuffer(ts_casters_binding, l->gpu_casters.gpuonly) .build(); quad.render( ctx, @@ -251,11 +260,11 @@ void Renderer::render( .rp_target(hdr_target, Clear_Mode::restore) .rp_depth_target(dev->get_depth_target(), Clear_Mode::restore) .build_rp(); - Render_Pass* shadow_passes[Lighting::max_shadows]; - for (i = 0; i < Lighting::max_shadows; i++) { + Render_Pass* shadow_passes[drawlist_count]; + for (i = SHADOW_MAP_START, j = 0; i < SHADOW_JIT_END; i++, j++) { shadow_passes[i] = &pb .begin_rp() - .rp_depth_target(l->shadow_slices[i], 1.0f) + .rp_depth_target(l->shadow_slices[j], 1.0f) .build_rp(); } @@ -263,20 +272,22 @@ void Renderer::render( drawlists[FORWARD].render(*this, dev, a, l, depth_prepass, 0); ctx.debug_pop(); + auto shadows = [&](int s, T cam) { + for (i = s, j = 0; j < l->caster_count; i++, j++) { + auto o = [](Pipeline_Builder& pb) { + pb.cull(Cull_Mode::front); + }; + setcam(i, l->casters[j].*cam); + ctx.debug_push("shadow map"); + drawlists[i].render(*this, dev, a, l, *shadow_passes[i], o); + ctx.debug_pop(); + } + }; ctx.debug_push("shadow maps"); - for ( - i = SHADOW_MAP_START, j = 0; - i < SHADOW_MAP_END && j < l->caster_count; - i++, j++ - ) { - auto o = [](Pipeline_Builder& pb) { - pb.cull(Cull_Mode::front); - }; - setcam(i, l->cameras[j]); - ctx.debug_push("shadow map"); - drawlists[i].render(*this, dev, a, l, *shadow_passes[j], o); - ctx.debug_pop(); - } + shadows(SHADOW_MAP_START, &Caster::reality); + ctx.debug_pop(); + ctx.debug_push("jittered shadow maps"); + shadows(SHADOW_JIT_START, &Caster::jittered); ctx.debug_pop(); temporal_shadows(dev, ctx, l, pb); diff --git a/renderer.hpp b/renderer.hpp index 387032d..20c7f98 100644 --- a/renderer.hpp +++ b/renderer.hpp @@ -10,7 +10,9 @@ enum { FORWARD, SHADOW_MAP_START, SHADOW_MAP_END = SHADOW_MAP_START + Lighting::max_shadows, - drawlist_count = SHADOW_MAP_END }; + SHADOW_JIT_START = SHADOW_MAP_END, + SHADOW_JIT_END = SHADOW_JIT_START + Lighting::max_shadows, + drawlist_count = SHADOW_JIT_END }; struct Asset_Arena; struct Model_Instance; @@ -64,6 +66,7 @@ struct Renderer { int ts_caster_config_binding; int ts_casters_binding; int ts_globals_binding; + int ts_prev_occlusion_binding; Sampler_Id ts_sampler; Staged_Buffer ts_config, ts_config2; diff --git a/sc/sc.cpp b/sc/sc.cpp index 9232e10..1f7ccba 100644 --- a/sc/sc.cpp +++ b/sc/sc.cpp @@ -601,7 +601,7 @@ struct Desc { size_t i, l = trgts.size(); for (i = 0; i < l; i++) { auto& attr = trgts[i]; - ss << "layout (location = 0) out "; + ss << "layout (location = " << i << ") out "; ss << attr.tname << " "; ss << attr.name << ";\n"; } diff --git a/src/guy.blend b/src/guy.blend new file mode 100644 index 0000000..a3b14ce Binary files /dev/null and b/src/guy.blend differ diff --git a/video.cpp b/video.cpp index 28df58b..3e960be 100644 --- a/video.cpp +++ b/video.cpp @@ -1628,8 +1628,8 @@ void Renderpass_Vk::init( const Rpo_Key& rpk ) { VkRenderPassCreateInfo ri{}; - VkAttachmentDescription ads[2]; - VkAttachmentReference car, dar; + VkAttachmentDescription ads[max_colour_attachments + 1]; + VkAttachmentReference cars[max_colour_attachments], dar; VkSubpassDescription sd{}; VkResult r; auto& rp = rpk.rpo; @@ -1637,10 +1637,12 @@ void Renderpass_Vk::init( bool has_depth = rp.depth.id; int count = 0, i, c = rp.colour_count; zero(ads, sizeof ads); + zero(cars, sizeof cars); for (i = 0; i < c; i++) { int index = count++; auto& colour = rp.colours[i]; auto& ad = ads[index]; + auto& car = cars[index]; ad.format = get_vk_format(colour.fmt); ad.samples = VK_SAMPLE_COUNT_1_BIT; ad.loadOp = load_op_from_mode(colour.mode); @@ -1677,7 +1679,7 @@ void Renderpass_Vk::init( sd.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; sd.colorAttachmentCount = rp.colour_count; - sd.pColorAttachments = &car; + sd.pColorAttachments = cars; sd.pDepthStencilAttachment = has_depth? &dar: 0; ri.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -1704,7 +1706,7 @@ void Framebuffer_Vk::init( ) { bool has_depth = rp.depth.id; int i, count = 0; - VkImageView atts[2]; + VkImageView atts[max_colour_attachments + 1]; VkResult r; VkFramebufferCreateInfo fbi{}; for (i = 0; i < rp.colour_count; i++) { @@ -2880,12 +2882,11 @@ void Pipeline_Vk::init_blending( zero(&bi, sizeof bi); if (rp.colour_count) { int i, c = rp.colour_count; - abs = - (VkPipelineColorBlendAttachmentState*)arena_alloc( + abs = (VkPipelineColorBlendAttachmentState*)arena_alloc( &scope, - sizeof abs * c + sizeof *abs * c ); - zero(abs, sizeof *abs); + zero(abs, sizeof *abs * c); for (i = 0; i < c; i++) { auto& ab = abs[i]; ab.colorWriteMask = diff --git a/video.hpp b/video.hpp index 5aa25bc..4289685 100644 --- a/video.hpp +++ b/video.hpp @@ -553,6 +553,7 @@ struct Context { void submit(const Render_Pass& rp); void copy(Buffer_Id dst, Buffer_Id src); void copy(Texture_Id dst, Buffer_Id src); + void copy(Texture_Id dst, Texture_Id src); void transition(Texture_Id id, Resource_State state); void debug_push(const char* name); void debug_pop(); -- cgit v1.2.3-54-g00ecf