added depth buffer and successfully used it in raymarcher

This commit is contained in:
Hopeless Tyromancy 2026-04-15 20:02:23 -04:00
parent 361e988930
commit 0bb9be2d36
10 changed files with 179 additions and 50 deletions

View File

@ -4,7 +4,7 @@ SHADER_DIR := shaders
BUILD_DIR := build BUILD_DIR := build
CXX := g++ 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 LDFLAGS := -lSDL3
GLSLC := glslc GLSLC := glslc

61
flake.lock generated Normal file
View File

@ -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
}

View File

@ -3,18 +3,22 @@
layout(location = 0) in vec2 uv; layout(location = 0) in vec2 uv;
layout(location = 0) out vec4 out_color; layout(location = 0) out vec4 out_color;
layout(set = 2, binding = 0) uniform sampler2D screen; 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 { layout(std140, set = 3, binding = 0) uniform UniformBlock {
mat4 model; mat4 model;
mat4 view; mat4 view;
mat4 projection; mat4 projection;
float time; mat4 inv_view;
mat4 inv_projection;
vec4 time_padded;
vec4 cam_pos;
}; };
float road(float x) { return cos(x); } float road(float x) { return cos(x); }
vec3 backup(vec2 uv) { vec3 backup(vec2 uv) {
float time = time_padded.x;
float x_scale = time * 12.0; float x_scale = time * 12.0;
float y_scale = uv.x; float y_scale = uv.x;
@ -36,7 +40,7 @@ const int MAX_MARCH_STEPS = 64;
const float EPS_DIST = 1e-6; const float EPS_DIST = 1e-6;
float sdf(vec3 point) { 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)); float size = 8.0 + (3.0* sin(time));
vec3 s1_local = mod(point, vec3(size)) - vec3(size/2.0); vec3 s1_local = mod(point, vec3(size)) - vec3(size/2.0);
float s1 = length(s1_local) - 0.3; float s1 = length(s1_local) - 0.3;
@ -54,14 +58,15 @@ vec3 getnormal(vec3 p) {
vec4 march(vec3 point, vec3 ray) { vec4 march(vec3 point, vec3 ray, float max_depth) {
float MAX_DEPTH = texture(screen, uv).w * 1000.0;
float totaldist = 0.0; float totaldist = 0.0;
int i; 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); float h = sdf(point);
point += h * ray; point += h * ray;
if (h + totaldist > max_depth)
break;
if (h < EPS_DIST) { if (h < EPS_DIST) {
return vec4(point, totaldist + h); return vec4(point, totaldist + h);
} }
@ -75,36 +80,37 @@ vec4 march(vec3 point, vec3 ray) {
vec3 camray() { vec3 camray() {
vec2 ndc = uv * 2.0 - 1.0; vec2 ndc = uv * 2.0 - 1.0;
ndc.y = -ndc.y; ndc.y = -ndc.y;
vec4 clip = vec4(ndc, 1.0, 1.0); vec4 view_pos = inv_projection * vec4(ndc, 1.0, 1.0);
vec4 view_pos = inverse(projection) * clip;
view_pos /= view_pos.w; view_pos /= view_pos.w;
return normalize((inv_view * vec4(normalize(view_pos.xyz), 0.0)).xyz);
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;
} }
vec3 camorigin() { return (inverse(view) * vec4(0, 0, 0, 1)).xyz; } vec4 kernel(float max_depth) {
max_depth = (max_depth > 0.0)? max_depth : 1000.0;
vec4 kernel() {
vec3 cam_pos = camorigin();
vec3 cam_ray = camray(); 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); } 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; vec2 bg = (projection * view * vec4(uv, 1.0, 1.0)).xy;
vec3 b = backup(bg); vec3 b = backup(bg);
vec4 hit = kernel(); float max_depth = linearize_depth(uv);
if (hit.w > 0.0 && ((t(uv.x, uv.y) < 0.01) || (hit.w < (texture(screen, uv).w * 1000.0)))) { vec4 hit = kernel(max_depth);
if (hit.w > 0.0) {
out_color = vec4(getnormal(hit.xyz), 1.0); out_color = vec4(getnormal(hit.xyz), 1.0);
} else { } else {
out_color = texture(screen, uv); out_color = texture(screen, uv);
} }
} }

View File

@ -8,7 +8,10 @@ layout(std140, set = 3, binding = 0) uniform UniformBlock {
mat4 model; mat4 model;
mat4 view; mat4 view;
mat4 projection; 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); } float t(float x, float y) { return length(texture(screen, vec2(x, y)).xyz); }

View File

@ -8,10 +8,13 @@ layout(location = 1) out float depth;
layout(location = 2) out vec3 v_normal_vs; // view-space normal layout(location = 2) out vec3 v_normal_vs; // view-space normal
layout(std140, set = 1, binding = 0) uniform UniformBlock { layout(std140, set = 1, binding = 0) uniform UniformBlock {
mat4 model; mat4 model;
mat4 view; mat4 view;
mat4 projection; mat4 projection;
float time; mat4 inv_view;
mat4 inv_projection;
vec4 time_padded;
vec4 cam_pos;
}; };
void main() { void main() {

View File

@ -18,7 +18,8 @@ void Camera::update() {
vec3 d = dir(); vec3 d = dir();
vec3 right = normalize(cross(d, up)); vec3 right = normalize(cross(d, up));
target = pos + d; 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; float speed = move_speed * shift_speed;
if (move_forward) { pos += d * speed; target += d * 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 { CameraUBO Camera::ubo(float aspect) const {
mat4 v = lookAt(pos, target, up);
mat4 p = perspective(radians(fov), aspect, 0.01f, 1000.0f);
return CameraUBO { return CameraUBO {
.model = mat4(1.0f), .model = mat4(1.0f),
.view = lookAt(pos, target, up), .view = v,
.proj = perspective(radians(fov), aspect, 0.01f, 1000.0f), .proj = p,
.time = (float)SDL_GetTicks() / 1000.0f, .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),
}; };
} }

View File

@ -48,9 +48,16 @@ void ScenePipeline::create(SDL_GPUDevice* dev, SDL_Window* win) {
.cull_mode = SDL_GPU_CULLMODE_NONE, .cull_mode = SDL_GPU_CULLMODE_NONE,
.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE, .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 = { .target_info = {
.color_target_descriptions = &color_tgt, .color_target_descriptions = &color_tgt,
.num_color_targets = 1, .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) { void BlitPipeline::create(SDL_GPUDevice* dev, SDL_Window* win) {
vert = load_shader(dev, "shaders/blit.vert.spv", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0); 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 { SDL_GPUColorTargetDescription color_tgt {
.format = SDL_GetGPUSwapchainTextureFormat(dev, win), .format = SDL_GetGPUSwapchainTextureFormat(dev, win),

View File

@ -15,6 +15,18 @@ bool Renderer::init(SDL_Window* w) {
load_obj(); load_obj();
render_sampler = create_linear_sampler(dev); 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); resize_render_texture(960, 540);
scene.create(dev, win); scene.create(dev, win);
@ -25,10 +37,11 @@ bool Renderer::init(SDL_Window* w) {
} }
void Renderer::destroy() { void Renderer::destroy() {
if (render_tex) SDL_ReleaseGPUTexture(dev, render_tex); if (render_tex) SDL_ReleaseGPUTexture(dev, render_tex);
if (post_tex) SDL_ReleaseGPUTexture(dev, post_tex); if (post_tex) SDL_ReleaseGPUTexture(dev, post_tex);
if (render_sampler) SDL_ReleaseGPUSampler(dev, render_sampler); 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); scene.destroy(dev);
blit.destroy(dev); blit.destroy(dev);
post.destroy(dev); post.destroy(dev);
@ -101,6 +114,19 @@ void Renderer::resize_render_texture(uint32_t w, uint32_t h) {
SDL_WaitForGPUIdle(dev); SDL_WaitForGPUIdle(dev);
if (render_tex) SDL_ReleaseGPUTexture(dev, render_tex); if (render_tex) SDL_ReleaseGPUTexture(dev, render_tex);
if (post_tex) SDL_ReleaseGPUTexture(dev, post_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); render_tex = create_render_texture(dev, win, w, h);
post_tex = create_render_texture(dev, win, w, h); post_tex = create_render_texture(dev, win, w, h);
render_w = w; render_w = w;
@ -117,8 +143,17 @@ void Renderer::pass_scene(SDL_GPUCommandBuffer* cmd, const CameraUBO& ubo) {
.load_op = SDL_GPU_LOADOP_CLEAR, .load_op = SDL_GPU_LOADOP_CLEAR,
.store_op = SDL_GPU_STOREOP_STORE, .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_BindGPUGraphicsPipeline(pass, scene.pipeline);
SDL_GPUBufferBinding binding { .buffer = vert_buff, .offset = 0 }; SDL_GPUBufferBinding binding { .buffer = vert_buff, .offset = 0 };
SDL_BindGPUVertexBuffers(pass, 0, &binding, 1); 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_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &tgt, 1, NULL);
SDL_BindGPUGraphicsPipeline(pass, blit.pipeline); SDL_BindGPUGraphicsPipeline(pass, blit.pipeline);
SDL_GPUTextureSamplerBinding tex { .texture = render_tex, .sampler = render_sampler }; SDL_GPUTextureSamplerBinding texs[2] = {
SDL_BindGPUFragmentSamplers(pass, 0, &tex, 1); { .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_DrawGPUPrimitives(pass, 3, 1, 0, 0);
SDL_EndGPURenderPass(pass); SDL_EndGPURenderPass(pass);
} }

View File

@ -15,7 +15,9 @@ struct Renderer {
SDL_GPUBuffer* vert_buff = nullptr; SDL_GPUBuffer* vert_buff = nullptr;
SDL_GPUTexture* render_tex = nullptr; SDL_GPUTexture* render_tex = nullptr;
SDL_GPUTexture* post_tex = nullptr; SDL_GPUTexture* post_tex = nullptr;
SDL_GPUTexture* depth_tex = nullptr;
SDL_GPUSampler* render_sampler = nullptr; SDL_GPUSampler* render_sampler = nullptr;
SDL_GPUSampler* depth_sampler = nullptr;
uint32_t render_w = 0, render_h = 0; uint32_t render_w = 0, render_h = 0;
std::vector<Vertex> vertices; std::vector<Vertex> vertices;

View File

@ -10,8 +10,11 @@ struct Vertex {
}; };
struct CameraUBO { struct CameraUBO {
mat4 model; mat4 model;
mat4 view; mat4 view;
mat4 proj; mat4 proj;
float time; mat4 inv_view;
}; mat4 inv_proj;
vec4 time;
vec4 cam_pos;
};