From 0bb9be2d362b7c00a248be56e7ecfa7ab93bd253 Mon Sep 17 00:00:00 2001 From: Hopeless Tyromancy Date: Wed, 15 Apr 2026 20:02:23 -0400 Subject: [PATCH] added depth buffer and successfully used it in raymarcher --- Makefile | 2 +- flake.lock | 61 ++++++++++++++++++++++++++++++++++++++++++++++ shaders/blit.frag | 58 +++++++++++++++++++++++-------------------- shaders/post.frag | 5 +++- shaders/scene.vert | 11 ++++++--- src/camera.cpp | 18 +++++++++----- src/pipelines.cpp | 9 ++++++- src/renderer.cpp | 50 ++++++++++++++++++++++++++++++++----- src/renderer.h | 2 ++ src/types.h | 13 ++++++---- 10 files changed, 179 insertions(+), 50 deletions(-) create mode 100644 flake.lock diff --git a/Makefile b/Makefile index 45a5dbf..2d9af9f 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ SHADER_DIR := shaders BUILD_DIR := build CXX := g++ -CXXFLAGS := -std=c++20 -Wall -Wextra -Wpedantic -Wno-missing-field-initializers -Wno-unused-function +CXXFLAGS := -g -std=c++20 -Wall -Wextra -Wpedantic -Wno-missing-field-initializers -Wno-unused-function LDFLAGS := -lSDL3 GLSLC := glslc diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..4cee253 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1776169885, + "narHash": "sha256-l/iNYDZ4bGOAFQY2q8y5OAfBBtrDAaPuRQqWaFHVRXM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4bd9165a9165d7b5e33ae57f3eecbcb28fb231c9", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/shaders/blit.frag b/shaders/blit.frag index b6dff6b..9aeaae0 100644 --- a/shaders/blit.frag +++ b/shaders/blit.frag @@ -3,18 +3,22 @@ layout(location = 0) in vec2 uv; layout(location = 0) out vec4 out_color; layout(set = 2, binding = 0) uniform sampler2D screen; +layout(set = 2, binding = 1) uniform sampler2D depth_tex; layout(std140, set = 3, binding = 0) uniform UniformBlock { - mat4 model; - mat4 view; - mat4 projection; - float time; + mat4 model; + mat4 view; + mat4 projection; + mat4 inv_view; + mat4 inv_projection; + vec4 time_padded; + vec4 cam_pos; }; - float road(float x) { return cos(x); } vec3 backup(vec2 uv) { + float time = time_padded.x; float x_scale = time * 12.0; float y_scale = uv.x; @@ -36,7 +40,7 @@ const int MAX_MARCH_STEPS = 64; const float EPS_DIST = 1e-6; float sdf(vec3 point) { -// return length(point - vec3(6.0 * sin(time), 8.0*abs(sin(time * 0.7)*cos(time)), 5.0 * cos(time * 1.2))) - 0.4; + float time = time_padded.x; float size = 8.0 + (3.0* sin(time)); vec3 s1_local = mod(point, vec3(size)) - vec3(size/2.0); float s1 = length(s1_local) - 0.3; @@ -54,14 +58,15 @@ vec3 getnormal(vec3 p) { -vec4 march(vec3 point, vec3 ray) { - float MAX_DEPTH = texture(screen, uv).w * 1000.0; +vec4 march(vec3 point, vec3 ray, float max_depth) { float totaldist = 0.0; int i; - for (i = 0; i < MAX_MARCH_STEPS && totaldist < MAX_DEPTH; i += 1) { + for (i = 0; i < MAX_MARCH_STEPS && totaldist < max_depth; i += 1) { float h = sdf(point); point += h * ray; + if (h + totaldist > max_depth) + break; if (h < EPS_DIST) { return vec4(point, totaldist + h); } @@ -75,36 +80,37 @@ vec4 march(vec3 point, vec3 ray) { vec3 camray() { vec2 ndc = uv * 2.0 - 1.0; ndc.y = -ndc.y; - vec4 clip = vec4(ndc, 1.0, 1.0); - vec4 view_pos = inverse(projection) * clip; + vec4 view_pos = inv_projection * vec4(ndc, 1.0, 1.0); view_pos /= view_pos.w; - - vec3 ray_dir_view = normalize(view_pos.xyz); - - vec3 ray_dir_world = normalize((inverse(view) * vec4(ray_dir_view, 0.0)).xyz); - - return ray_dir_world; + return normalize((inv_view * vec4(normalize(view_pos.xyz), 0.0)).xyz); } -vec3 camorigin() { return (inverse(view) * vec4(0, 0, 0, 1)).xyz; } - -vec4 kernel() { - vec3 cam_pos = camorigin(); +vec4 kernel(float max_depth) { + max_depth = (max_depth > 0.0)? max_depth : 1000.0; vec3 cam_ray = camray(); - return march(cam_pos, cam_ray); + return march(cam_pos.xyz, cam_ray, max_depth); } float t(float x, float y) { return length(texture(screen, vec2(x, y)).xyz); } -void main() { +float linearize_depth(vec2 uv) { + float d = texture(depth_tex, uv).r; + if (d >= 1.0) return 1000.0; // nothing written + vec4 ndc = vec4((uv * 2.0 - 1.0), d * 2.0 - 1.0, 1.0); + vec4 view_pos = inv_projection * ndc; + view_pos /= view_pos.w; + return -view_pos.z; // view space, positive distance +} +void main() { vec2 bg = (projection * view * vec4(uv, 1.0, 1.0)).xy; vec3 b = backup(bg); - vec4 hit = kernel(); - if (hit.w > 0.0 && ((t(uv.x, uv.y) < 0.01) || (hit.w < (texture(screen, uv).w * 1000.0)))) { + float max_depth = linearize_depth(uv); + vec4 hit = kernel(max_depth); + if (hit.w > 0.0) { out_color = vec4(getnormal(hit.xyz), 1.0); } else { out_color = texture(screen, uv); } -} +} \ No newline at end of file diff --git a/shaders/post.frag b/shaders/post.frag index 30c978e..b2e0523 100644 --- a/shaders/post.frag +++ b/shaders/post.frag @@ -8,7 +8,10 @@ layout(std140, set = 3, binding = 0) uniform UniformBlock { mat4 model; mat4 view; mat4 projection; - float time; + mat4 inv_view; + mat4 inv_projection; + vec4 time_padded; + vec4 cam_pos; }; float t(float x, float y) { return length(texture(screen, vec2(x, y)).xyz); } diff --git a/shaders/scene.vert b/shaders/scene.vert index b6faca0..1e151a1 100644 --- a/shaders/scene.vert +++ b/shaders/scene.vert @@ -8,10 +8,13 @@ layout(location = 1) out float depth; layout(location = 2) out vec3 v_normal_vs; // view-space normal layout(std140, set = 1, binding = 0) uniform UniformBlock { - mat4 model; - mat4 view; - mat4 projection; - float time; + mat4 model; + mat4 view; + mat4 projection; + mat4 inv_view; + mat4 inv_projection; + vec4 time_padded; + vec4 cam_pos; }; void main() { diff --git a/src/camera.cpp b/src/camera.cpp index 94fb750..ae6d36e 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -18,7 +18,8 @@ void Camera::update() { vec3 d = dir(); vec3 right = normalize(cross(d, up)); target = pos + d; - float shift_speed = shifted? 10.0 : 1.0; + + float shift_speed = shifted? 100.0 : 1.0; float speed = move_speed * shift_speed; if (move_forward) { pos += d * speed; target += d * speed; } @@ -56,10 +57,15 @@ void Camera::on_mouse_motion(float dx, float dy) { } CameraUBO Camera::ubo(float aspect) const { + mat4 v = lookAt(pos, target, up); + mat4 p = perspective(radians(fov), aspect, 0.01f, 1000.0f); return CameraUBO { - .model = mat4(1.0f), - .view = lookAt(pos, target, up), - .proj = perspective(radians(fov), aspect, 0.01f, 1000.0f), - .time = (float)SDL_GetTicks() / 1000.0f, + .model = mat4(1.0f), + .view = v, + .proj = p, + .inv_view = inverse(v), + .inv_proj = inverse(p), + .time = vec4((float)SDL_GetTicks() / 1000.0f, 0.0, 0.0, 0.0), + .cam_pos = vec4(pos, 1.0), }; -} +} \ No newline at end of file diff --git a/src/pipelines.cpp b/src/pipelines.cpp index cb535b1..b2d906e 100644 --- a/src/pipelines.cpp +++ b/src/pipelines.cpp @@ -48,9 +48,16 @@ void ScenePipeline::create(SDL_GPUDevice* dev, SDL_Window* win) { .cull_mode = SDL_GPU_CULLMODE_NONE, .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE, }, + .depth_stencil_state = { + .compare_op = SDL_GPU_COMPAREOP_LESS, + .enable_depth_test = true, + .enable_depth_write = true, + }, .target_info = { .color_target_descriptions = &color_tgt, .num_color_targets = 1, + .depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT, + .has_depth_stencil_target = true, }, }; @@ -67,7 +74,7 @@ void ScenePipeline::destroy(SDL_GPUDevice* dev) { void BlitPipeline::create(SDL_GPUDevice* dev, SDL_Window* win) { vert = load_shader(dev, "shaders/blit.vert.spv", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0); - frag = load_shader(dev, "shaders/blit.frag.spv", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1); + frag = load_shader(dev, "shaders/blit.frag.spv", SDL_GPU_SHADERSTAGE_FRAGMENT, 2, 1); SDL_GPUColorTargetDescription color_tgt { .format = SDL_GetGPUSwapchainTextureFormat(dev, win), diff --git a/src/renderer.cpp b/src/renderer.cpp index adf235f..972aa7e 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -15,6 +15,18 @@ bool Renderer::init(SDL_Window* w) { load_obj(); render_sampler = create_linear_sampler(dev); + SDL_GPUSamplerCreateInfo depth_sampler_info { + .min_filter = SDL_GPU_FILTER_NEAREST, + .mag_filter = SDL_GPU_FILTER_NEAREST, + .mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, + .address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE, + .address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE, + .compare_op = SDL_GPU_COMPAREOP_INVALID, + .enable_compare = false, + }; + depth_sampler = SDL_CreateGPUSampler(dev, &depth_sampler_info); + + resize_render_texture(960, 540); scene.create(dev, win); @@ -25,10 +37,11 @@ bool Renderer::init(SDL_Window* w) { } void Renderer::destroy() { - if (render_tex) SDL_ReleaseGPUTexture(dev, render_tex); - if (post_tex) SDL_ReleaseGPUTexture(dev, post_tex); + if (render_tex) SDL_ReleaseGPUTexture(dev, render_tex); + if (post_tex) SDL_ReleaseGPUTexture(dev, post_tex); if (render_sampler) SDL_ReleaseGPUSampler(dev, render_sampler); - if (vert_buff) SDL_ReleaseGPUBuffer(dev, vert_buff); + if (vert_buff) SDL_ReleaseGPUBuffer(dev, vert_buff); + if (depth_tex) SDL_ReleaseGPUTexture(dev, depth_tex); scene.destroy(dev); blit.destroy(dev); post.destroy(dev); @@ -101,6 +114,19 @@ void Renderer::resize_render_texture(uint32_t w, uint32_t h) { SDL_WaitForGPUIdle(dev); if (render_tex) SDL_ReleaseGPUTexture(dev, render_tex); if (post_tex) SDL_ReleaseGPUTexture(dev, post_tex); + if (depth_tex) SDL_ReleaseGPUTexture(dev, depth_tex); + + SDL_GPUTextureCreateInfo depth_info { + .type = SDL_GPU_TEXTURETYPE_2D, + .format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT, + .usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER, + .width = w, + .height = h, + .layer_count_or_depth = 1, + .num_levels = 1, + }; + + depth_tex = SDL_CreateGPUTexture(dev, &depth_info); render_tex = create_render_texture(dev, win, w, h); post_tex = create_render_texture(dev, win, w, h); render_w = w; @@ -117,8 +143,17 @@ void Renderer::pass_scene(SDL_GPUCommandBuffer* cmd, const CameraUBO& ubo) { .load_op = SDL_GPU_LOADOP_CLEAR, .store_op = SDL_GPU_STOREOP_STORE, }; + + SDL_GPUDepthStencilTargetInfo depth_tgt { + .texture = depth_tex, + .clear_depth = 1.0f, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE, + .stencil_load_op = SDL_GPU_LOADOP_DONT_CARE, + .stencil_store_op = SDL_GPU_STOREOP_STORE, + }; - SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &tgt, 1, NULL); + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &tgt, 1, &depth_tgt); SDL_BindGPUGraphicsPipeline(pass, scene.pipeline); SDL_GPUBufferBinding binding { .buffer = vert_buff, .offset = 0 }; SDL_BindGPUVertexBuffers(pass, 0, &binding, 1); @@ -137,8 +172,11 @@ void Renderer::pass_blit(SDL_GPUCommandBuffer* cmd, const CameraUBO& ubo) { SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &tgt, 1, NULL); SDL_BindGPUGraphicsPipeline(pass, blit.pipeline); - SDL_GPUTextureSamplerBinding tex { .texture = render_tex, .sampler = render_sampler }; - SDL_BindGPUFragmentSamplers(pass, 0, &tex, 1); + SDL_GPUTextureSamplerBinding texs[2] = { + { .texture = render_tex, .sampler = render_sampler }, + { .texture = depth_tex, .sampler = depth_sampler }, + }; + SDL_BindGPUFragmentSamplers(pass, 0, texs, 2); SDL_DrawGPUPrimitives(pass, 3, 1, 0, 0); SDL_EndGPURenderPass(pass); } diff --git a/src/renderer.h b/src/renderer.h index 09f1ef1..90cafcf 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -15,7 +15,9 @@ struct Renderer { SDL_GPUBuffer* vert_buff = nullptr; SDL_GPUTexture* render_tex = nullptr; SDL_GPUTexture* post_tex = nullptr; + SDL_GPUTexture* depth_tex = nullptr; SDL_GPUSampler* render_sampler = nullptr; + SDL_GPUSampler* depth_sampler = nullptr; uint32_t render_w = 0, render_h = 0; std::vector vertices; diff --git a/src/types.h b/src/types.h index 2315cbd..d720d6d 100644 --- a/src/types.h +++ b/src/types.h @@ -10,8 +10,11 @@ struct Vertex { }; struct CameraUBO { - mat4 model; - mat4 view; - mat4 proj; - float time; -}; + mat4 model; + mat4 view; + mat4 proj; + mat4 inv_view; + mat4 inv_proj; + vec4 time; + vec4 cam_pos; +}; \ No newline at end of file