diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-03 19:55:42 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-03 19:55:42 +0100 |
| commit | 1bb4cc54a86c4e23dc815d305bf753fd2fee689a (patch) | |
| tree | 261cfd37134defb54f92e5cd1057ebd969d689a6 /src/3d | |
| parent | 4fe647e13e3483e7fe01e6466c3871a20892963f (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')
| -rw-r--r-- | src/3d/renderer.cc | 136 |
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); } |
