diff options
Diffstat (limited to 'src/3d')
| -rw-r--r-- | src/3d/renderer.cc | 189 | ||||
| -rw-r--r-- | src/3d/renderer.h | 21 |
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 |
