summaryrefslogtreecommitdiff
path: root/src/3d
diff options
context:
space:
mode:
Diffstat (limited to 'src/3d')
-rw-r--r--src/3d/renderer.cc189
-rw-r--r--src/3d/renderer.h21
2 files changed, 158 insertions, 52 deletions
diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc
index 684fda9..9dfc1f8 100644
--- a/src/3d/renderer.cc
+++ b/src/3d/renderer.cc
@@ -133,6 +133,8 @@ void Renderer3D::shutdown() {
wgpuSamplerRelease(default_sampler_);
if (pipeline_)
wgpuRenderPipelineRelease(pipeline_);
+ if (pipeline_no_bvh_)
+ wgpuRenderPipelineRelease(pipeline_no_bvh_);
if (bind_group_)
wgpuBindGroupRelease(bind_group_);
if (skybox_pipeline_)
@@ -143,6 +145,8 @@ void Renderer3D::shutdown() {
wgpuBufferRelease(global_uniform_buffer_);
if (object_storage_buffer_)
wgpuBufferRelease(object_storage_buffer_);
+ if (bvh_storage_buffer_)
+ wgpuBufferRelease(bvh_storage_buffer_);
if (depth_view_)
wgpuTextureViewRelease(depth_view_);
if (depth_texture_)
@@ -189,6 +193,10 @@ void Renderer3D::create_default_resources() {
WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst,
nullptr)
.buffer;
+ bvh_storage_buffer_ = gpu_create_buffer(
+ device_, sizeof(BVHNode) * kMaxObjects * 2, // Capacity for a full tree
+ WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst, nullptr)
+ .buffer;
}
void Renderer3D::set_noise_texture(WGPUTextureView noise_view) {
@@ -207,34 +215,75 @@ void Renderer3D::add_debug_aabb(const vec3& min, const vec3& max,
}
void Renderer3D::create_pipeline() {
- WGPUBindGroupLayoutEntry entries[5] = {};
- entries[0].binding = 0;
- entries[0].visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment;
- entries[0].buffer.type = WGPUBufferBindingType_Uniform;
- entries[0].buffer.minBindingSize = sizeof(GlobalUniforms);
+ pipeline_ = create_pipeline_impl(true); // BVH enabled
+ pipeline_no_bvh_ = create_pipeline_impl(false); // BVH disabled
+}
- entries[1].binding = 1;
- entries[1].visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment;
- entries[1].buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
- entries[1].buffer.minBindingSize = sizeof(ObjectData) * kMaxObjects;
+WGPURenderPipeline Renderer3D::create_pipeline_impl(bool use_bvh) {
+ std::vector<WGPUBindGroupLayoutEntry> entries;
- entries[2].binding = 2;
- entries[2].visibility = WGPUShaderStage_Fragment;
- entries[2].texture.sampleType = WGPUTextureSampleType_Float;
- entries[2].texture.viewDimension = WGPUTextureViewDimension_2D;
+ // Binding 0: Global Uniforms
+ {
+ WGPUBindGroupLayoutEntry e = {};
+ e.binding = 0;
+ e.visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment;
+ e.buffer.type = WGPUBufferBindingType_Uniform;
+ e.buffer.minBindingSize = sizeof(GlobalUniforms);
+ entries.push_back(e);
+ }
+
+ // Binding 1: Object Data
+ {
+ WGPUBindGroupLayoutEntry e = {};
+ e.binding = 1;
+ e.visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment;
+ e.buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
+ e.buffer.minBindingSize = sizeof(ObjectData) * kMaxObjects;
+ entries.push_back(e);
+ }
+
+ // Binding 2: BVH Nodes (only if BVH is used)
+ if (use_bvh) {
+ WGPUBindGroupLayoutEntry e = {};
+ e.binding = 2;
+ e.visibility = WGPUShaderStage_Fragment;
+ e.buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
+ e.buffer.minBindingSize = sizeof(BVHNode) * kMaxObjects * 2;
+ entries.push_back(e);
+ }
- entries[3].binding = 3;
- entries[3].visibility = WGPUShaderStage_Fragment;
- entries[3].sampler.type = WGPUSamplerBindingType_Filtering;
+ // Binding 3: Noise Texture
+ {
+ WGPUBindGroupLayoutEntry e = {};
+ e.binding = 3;
+ e.visibility = WGPUShaderStage_Fragment;
+ e.texture.sampleType = WGPUTextureSampleType_Float;
+ e.texture.viewDimension = WGPUTextureViewDimension_2D;
+ entries.push_back(e);
+ }
- entries[4].binding = 4;
- entries[4].visibility = WGPUShaderStage_Fragment;
- entries[4].texture.sampleType = WGPUTextureSampleType_Float;
- entries[4].texture.viewDimension = WGPUTextureViewDimension_2D;
+ // Binding 4: Default Sampler
+ {
+ WGPUBindGroupLayoutEntry e = {};
+ e.binding = 4;
+ e.visibility = WGPUShaderStage_Fragment;
+ e.sampler.type = WGPUSamplerBindingType_Filtering;
+ entries.push_back(e);
+ }
+
+ // Binding 5: Sky Texture
+ {
+ WGPUBindGroupLayoutEntry e = {};
+ e.binding = 5;
+ e.visibility = WGPUShaderStage_Fragment;
+ e.texture.sampleType = WGPUTextureSampleType_Float;
+ e.texture.viewDimension = WGPUTextureViewDimension_2D;
+ entries.push_back(e);
+ }
WGPUBindGroupLayoutDescriptor bgl_desc = {};
- bgl_desc.entryCount = 5;
- bgl_desc.entries = entries;
+ bgl_desc.entryCount = (uint32_t)entries.size();
+ bgl_desc.entries = entries.data();
WGPUBindGroupLayout bgl = wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc);
WGPUPipelineLayoutDescriptor pl_desc = {};
@@ -246,7 +295,18 @@ void Renderer3D::create_pipeline() {
const char* asset_data =
(const char*)GetAsset(AssetId::ASSET_SHADER_RENDERER_3D);
std::string main_code = asset_data;
- std::string shader_source = ShaderComposer::Get().Compose({}, main_code);
+
+ // Use ShaderComposer to dynamically include the correct scene_query snippet
+ ShaderComposer::CompositionMap composition_map;
+ if (use_bvh) {
+ composition_map["render/scene_query_mode"] = "render/scene_query_bvh";
+ } else {
+ composition_map["render/scene_query_mode"] = "render/scene_query_linear";
+ }
+ std::string shader_source = ShaderComposer::Get().Compose({}, main_code, composition_map);
+
+ // DEBUG: Print shader source to check for include errors
+ std::cout << "Shader Source (BVH=" << use_bvh << "):" << std::endl << shader_source << std::endl;
#if defined(DEMO_CROSS_COMPILE_WIN32)
WGPUShaderModuleWGSLDescriptor wgsl_desc = {};
@@ -297,10 +357,12 @@ void Renderer3D::create_pipeline() {
desc.multisample.count = 1;
desc.multisample.mask = 0xFFFFFFFF;
- pipeline_ = wgpuDeviceCreateRenderPipeline(device_, &desc);
+ WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(device_, &desc);
wgpuBindGroupLayoutRelease(bgl);
wgpuPipelineLayoutRelease(pipeline_layout);
wgpuShaderModuleRelease(shader_module);
+
+ return pipeline;
}
void Renderer3D::update_uniforms(const Scene& scene, const Camera& camera,
@@ -346,6 +408,13 @@ void Renderer3D::update_uniforms(const Scene& scene, const Camera& camera,
wgpuQueueWriteBuffer(queue_, object_storage_buffer_, 0, obj_data.data(),
obj_data.size() * sizeof(ObjectData));
}
+
+ // Build and upload BVH (always uploaded, used by BVH pipeline)
+ BVHBuilder::build(cpu_bvh_, scene.objects);
+ if (!cpu_bvh_.nodes.empty()) {
+ wgpuQueueWriteBuffer(queue_, bvh_storage_buffer_, 0, cpu_bvh_.nodes.data(),
+ cpu_bvh_.nodes.size() * sizeof(BVHNode));
+ }
}
void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene,
@@ -357,36 +426,70 @@ void Renderer3D::draw(WGPURenderPassEncoder pass, const Scene& scene,
if (bind_group_)
wgpuBindGroupRelease(bind_group_);
- WGPUBindGroupEntry bg_entries[5] = {};
+ std::vector<WGPUBindGroupEntry> bg_entries;
+
+ {
+ WGPUBindGroupEntry e = {};
+ e.binding = 0;
+ e.buffer = global_uniform_buffer_;
+ e.size = sizeof(GlobalUniforms);
+ bg_entries.push_back(e);
+ }
- bg_entries[0].binding = 0;
- bg_entries[0].buffer = global_uniform_buffer_;
- bg_entries[0].size = sizeof(GlobalUniforms);
+ {
+ WGPUBindGroupEntry e = {};
+ e.binding = 1;
+ e.buffer = object_storage_buffer_;
+ e.size = sizeof(ObjectData) * kMaxObjects;
+ bg_entries.push_back(e);
+ }
- bg_entries[1].binding = 1;
- bg_entries[1].buffer = object_storage_buffer_;
- bg_entries[1].size = sizeof(ObjectData) * kMaxObjects;
+ if (bvh_enabled_) {
+ WGPUBindGroupEntry e = {};
+ e.binding = 2;
+ e.buffer = bvh_storage_buffer_;
+ e.size = sizeof(BVHNode) * kMaxObjects * 2;
+ bg_entries.push_back(e);
+ }
- bg_entries[2].binding = 2;
- bg_entries[2].textureView = noise_texture_view_;
+ {
+ WGPUBindGroupEntry e = {};
+ e.binding = 3;
+ e.textureView = noise_texture_view_;
+ bg_entries.push_back(e);
+ }
- bg_entries[3].binding = 3;
- bg_entries[3].sampler = default_sampler_;
+ {
+ WGPUBindGroupEntry e = {};
+ e.binding = 4;
+ e.sampler = default_sampler_;
+ bg_entries.push_back(e);
+ }
+
+ {
+ WGPUBindGroupEntry e = {};
+ e.binding = 5;
+ e.textureView =
+ sky_texture_view_ ? sky_texture_view_ : noise_texture_view_;
+ bg_entries.push_back(e);
+ }
- bg_entries[4].binding = 4;
- bg_entries[4].textureView =
- sky_texture_view_ ? sky_texture_view_ : noise_texture_view_; // Fallback
+ // Select the correct pipeline and bind group layout
+ WGPURenderPipeline current_pipeline =
+ bvh_enabled_ ? pipeline_ : pipeline_no_bvh_;
+ WGPUBindGroupLayout current_layout =
+ wgpuRenderPipelineGetBindGroupLayout(current_pipeline, 0);
WGPUBindGroupDescriptor bg_desc = {};
- bg_desc.layout = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0);
- bg_desc.entryCount = 5;
- bg_desc.entries = bg_entries;
+ bg_desc.layout = current_layout;
+ bg_desc.entryCount = (uint32_t)bg_entries.size();
+ bg_desc.entries = bg_entries.data();
bind_group_ = wgpuDeviceCreateBindGroup(device_, &bg_desc);
- wgpuBindGroupLayoutRelease(bg_desc.layout);
+ wgpuBindGroupLayoutRelease(current_layout);
- wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
+ wgpuRenderPassEncoderSetPipeline(pass, current_pipeline);
wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr);
diff --git a/src/3d/renderer.h b/src/3d/renderer.h
index 8068bdc..db86b72 100644
--- a/src/3d/renderer.h
+++ b/src/3d/renderer.h
@@ -6,6 +6,7 @@
#include "3d/camera.h"
#include "3d/scene.h"
+#include "3d/bvh.h"
#include "gpu/gpu.h"
#include <vector>
@@ -43,19 +44,12 @@ class Renderer3D {
#endif
// Renders the scene to the given texture view (Convenience: creates a pass)
-
void render(const Scene& scene, const Camera& camera, float time,
-
WGPUTextureView target_view,
WGPUTextureView depth_view_opt = nullptr);
// Records draw commands to an existing pass.
-
// Assumes the pass has a compatible pipeline (or we set it here).
-
- // Note: Caller must ensure depth/color attachments are set up correctly in
- // the pass.
-
void draw(WGPURenderPassEncoder pass, const Scene& scene,
const Camera& camera, float time);
@@ -67,8 +61,12 @@ class Renderer3D {
// Resize handler (if needed for internal buffers)
void resize(int width, int height);
+ // Set whether to use BVH acceleration
+ void SetBvhEnabled(bool enabled) { bvh_enabled_ = enabled; }
+
private:
void create_pipeline();
+ WGPURenderPipeline create_pipeline_impl(bool use_bvh);
void create_skybox_pipeline();
void create_default_resources();
void update_uniforms(const Scene& scene, const Camera& camera, float time);
@@ -77,12 +75,17 @@ class Renderer3D {
WGPUQueue queue_ = nullptr;
WGPUTextureFormat format_ = WGPUTextureFormat_Undefined;
- WGPURenderPipeline pipeline_ = nullptr;
+ WGPURenderPipeline pipeline_ = nullptr; // BVH enabled
+ WGPURenderPipeline pipeline_no_bvh_ = nullptr; // BVH disabled
WGPUBindGroup bind_group_ = nullptr;
WGPURenderPipeline skybox_pipeline_ = nullptr;
WGPUBindGroup skybox_bind_group_ = nullptr;
WGPUBuffer global_uniform_buffer_ = nullptr;
WGPUBuffer object_storage_buffer_ = nullptr;
+ WGPUBuffer bvh_storage_buffer_ = nullptr;
+
+ BVH cpu_bvh_; // Keep a CPU-side copy for building/uploading
+ bool bvh_enabled_ = true;
WGPUTextureView noise_texture_view_ = nullptr;
WGPUTextureView sky_texture_view_ = nullptr;
@@ -101,4 +104,4 @@ class Renderer3D {
VisualDebug visual_debug_;
static bool s_debug_enabled_;
#endif
-};
+}; \ No newline at end of file