summaryrefslogtreecommitdiff
path: root/src/3d/renderer.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-03 19:55:42 +0100
committerskal <pascal.massimino@gmail.com>2026-02-03 19:55:42 +0100
commit1bb4cc54a86c4e23dc815d305bf753fd2fee689a (patch)
tree261cfd37134defb54f92e5cd1057ebd969d689a6 /src/3d/renderer.cc
parent4fe647e13e3483e7fe01e6466c3871a20892963f (diff)
fix: Resolve skybox and floor rendering bugs with two-pass approach
- Implemented a two-pass rendering strategy in Renderer3D::render: - First pass renders the skybox without depth writes. - Second pass renders scene objects with proper depth testing. - Ensured skybox pipeline explicitly ignores depth via . - Corrected struct in C++ and WGSL for and padding, resolving validation errors. - Reverted to for SDF misses, preventing sky bleed-through. - Updated to include a SKYBOX object with Perlin noise. handoff(Gemini): Resolved rendering bugs. Skybox renders correctly as background, and scene objects (including floor) are now visible. Codebase stable.
Diffstat (limited to 'src/3d/renderer.cc')
-rw-r--r--src/3d/renderer.cc136
1 files changed, 108 insertions, 28 deletions
diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc
index 11df2d8..79d59d9 100644
--- a/src/3d/renderer.cc
+++ b/src/3d/renderer.cc
@@ -111,7 +111,7 @@ void Renderer3D::create_skybox_pipeline() {
desc.primitive.frontFace = WGPUFrontFace_CCW;
desc.multisample.count = 1;
desc.multisample.mask = 0xFFFFFFFF;
- // Important: No depth/stencil state for skybox, or depthWriteEnabled = false
+ desc.depthStencil = nullptr; // Explicitly no depth for skybox
skybox_pipeline_ = wgpuDeviceCreateRenderPipeline(device_, &desc);
wgpuBindGroupLayoutRelease(bgl);
@@ -403,69 +403,149 @@ void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene,
}
void Renderer3D::render(const Scene& scene, const Camera& camera, float time,
+
WGPUTextureView target_view,
+
WGPUTextureView depth_view_opt) {
WGPUTextureView depth_view = depth_view_opt ? depth_view_opt : depth_view_;
if (!depth_view)
+
return;
- WGPURenderPassColorAttachment color_attachment = {};
- gpu_init_color_attachment(color_attachment, target_view);
- color_attachment.clearValue = {0.0f, 0.0f, 0.0f, 1.0f}; // Clear to black
+ WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device_, nullptr);
- WGPURenderPassDepthStencilAttachment depth_attachment = {};
- depth_attachment.view = depth_view;
- depth_attachment.depthLoadOp = WGPULoadOp_Clear;
- depth_attachment.depthStoreOp = WGPUStoreOp_Store;
- depth_attachment.depthClearValue = 1.0f;
+ // --- Pass 1: Render Skybox (Clears color, no depth write) ---
- WGPURenderPassDescriptor pass_desc = {};
- pass_desc.colorAttachmentCount = 1;
- pass_desc.colorAttachments = &color_attachment;
- pass_desc.depthStencilAttachment = &depth_attachment;
+ if (sky_texture_view_ && skybox_pipeline_) {
+ WGPURenderPassColorAttachment sky_color_attachment = {};
- WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device_, nullptr);
- WGPURenderPassEncoder pass =
- wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc);
+ gpu_init_color_attachment(sky_color_attachment, target_view);
- wgpuRenderPassEncoderSetViewport(pass, 0.0f, 0.0f, (float)width_,
- (float)height_, 0.0f, 1.0f);
+ sky_color_attachment.loadOp = WGPULoadOp_Clear;
+
+ sky_color_attachment.storeOp = WGPUStoreOp_Store;
+
+ sky_color_attachment.clearValue = {0.0f, 0.0f, 0.0f,
+ 1.0f}; // Clear to black
+
+ // Only clear depth, don't store it for the skybox pass
+
+ WGPURenderPassDepthStencilAttachment sky_depth_attachment = {};
+
+ sky_depth_attachment.view = depth_view;
+
+ sky_depth_attachment.depthLoadOp = WGPULoadOp_Clear;
+
+ sky_depth_attachment.depthStoreOp =
+ WGPUStoreOp_Discard; // Don't store depth
+
+ sky_depth_attachment.depthClearValue = 1.0f;
+
+ WGPURenderPassDescriptor sky_pass_desc = {};
+
+ sky_pass_desc.colorAttachmentCount = 1;
+
+ sky_pass_desc.colorAttachments = &sky_color_attachment;
+
+ sky_pass_desc.depthStencilAttachment = &sky_depth_attachment;
+
+ WGPURenderPassEncoder sky_pass =
+ wgpuCommandEncoderBeginRenderPass(encoder, &sky_pass_desc);
+
+ wgpuRenderPassEncoderSetViewport(sky_pass, 0.0f, 0.0f, (float)width_,
+
+ (float)height_, 0.0f, 1.0f);
- // --- Render Skybox First (no depth write) ---
- if (sky_texture_view_ && skybox_pipeline_) {
if (skybox_bind_group_)
wgpuBindGroupRelease(skybox_bind_group_);
WGPUBindGroupEntry bg_entries[3] = {};
+
bg_entries[0].binding = 0;
+
bg_entries[0].textureView = sky_texture_view_;
+
bg_entries[1].binding = 1;
+
bg_entries[1].sampler = default_sampler_;
+
bg_entries[2].binding = 2;
+
bg_entries[2].buffer = global_uniform_buffer_;
+
bg_entries[2].size = sizeof(GlobalUniforms);
WGPUBindGroupDescriptor bg_desc = {};
+
bg_desc.layout = wgpuRenderPipelineGetBindGroupLayout(skybox_pipeline_, 0);
+
bg_desc.entryCount = 3;
+
bg_desc.entries = bg_entries;
+
skybox_bind_group_ = wgpuDeviceCreateBindGroup(device_, &bg_desc);
+
wgpuBindGroupLayoutRelease(bg_desc.layout);
- wgpuRenderPassEncoderSetPipeline(pass, skybox_pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, skybox_bind_group_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); // Draw a full-screen quad
+ wgpuRenderPassEncoderSetPipeline(sky_pass, skybox_pipeline_);
+
+ wgpuRenderPassEncoderSetBindGroup(sky_pass, 0, skybox_bind_group_, 0,
+ nullptr);
+
+ wgpuRenderPassEncoderDraw(sky_pass, 3, 1, 0, 0); // Draw a full-screen quad
+
+ wgpuRenderPassEncoderEnd(sky_pass);
+
+ wgpuRenderPassEncoderRelease(sky_pass);
}
- // --- Render Scene Objects (with depth write) ---
- // The main pipeline always has depth writing enabled by default.
- draw(pass, scene, camera, time);
+ // --- Pass 2: Render Scene Objects (Loads depth, writes depth) ---
+
+ WGPURenderPassColorAttachment obj_color_attachment = {};
+
+ gpu_init_color_attachment(obj_color_attachment, target_view);
+
+ obj_color_attachment.loadOp = WGPULoadOp_Load; // Load from previous pass
+
+ obj_color_attachment.storeOp = WGPUStoreOp_Store;
+
+ WGPURenderPassDepthStencilAttachment obj_depth_attachment = {};
+
+ obj_depth_attachment.view = depth_view;
+
+ obj_depth_attachment.depthLoadOp = WGPULoadOp_Load; // Load cleared depth
+
+ obj_depth_attachment.depthStoreOp = WGPUStoreOp_Store; // Store depth
+
+ obj_depth_attachment.depthClearValue = 1.0f;
+
+ WGPURenderPassDescriptor obj_pass_desc = {};
+
+ obj_pass_desc.colorAttachmentCount = 1;
+
+ obj_pass_desc.colorAttachments = &obj_color_attachment;
+
+ obj_pass_desc.depthStencilAttachment = &obj_depth_attachment;
+
+ WGPURenderPassEncoder obj_pass =
+ wgpuCommandEncoderBeginRenderPass(encoder, &obj_pass_desc);
+
+ wgpuRenderPassEncoderSetViewport(obj_pass, 0.0f, 0.0f, (float)width_,
+
+ (float)height_, 0.0f, 1.0f);
+
+ draw(obj_pass, scene, camera, time);
+
+ wgpuRenderPassEncoderEnd(obj_pass);
+
+ wgpuRenderPassEncoderRelease(obj_pass);
- wgpuRenderPassEncoderEnd(pass);
WGPUCommandBuffer commands = wgpuCommandEncoderFinish(encoder, nullptr);
+
wgpuQueueSubmit(queue_, 1, &commands);
- wgpuRenderPassEncoderRelease(pass);
+
wgpuCommandBufferRelease(commands);
+
wgpuCommandEncoderRelease(encoder);
}