From a6655eebe2a69ee427264bd43df5747851ed96df Mon Sep 17 00:00:00 2001 From: hachem Date: Fri, 15 Aug 2025 03:18:29 +0200 Subject: feat: complete first geodesic 3D raytracing --- src/engine/engine.cpp | 317 ++++++++++++++++++-------------------------------- 1 file changed, 113 insertions(+), 204 deletions(-) (limited to 'src/engine/engine.cpp') diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 29fa65a..c2a84a8 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1,251 +1,144 @@ -#include "engine.h" -#include -#include #include #include #include -#include + +#include + +#include "engine.h" #include "rendering/vertex_buffer.h" #include "rendering/index_buffer.h" namespace Donut { - Engine::Engine() - : m_sag_a(glm::vec3(0.0f, 0.0f, 0.0f), - static_cast(8.54e36)) + Engine::Engine() + : m_sag_a(glm::vec3(0.0f, 0.0f, 0.0f), 8.54e36f) { GLFWwindow* window = static_cast(Application::get().get_window().get_native_window()); glfwGetFramebufferSize(window, &m_width, &m_height); - m_compute_height = 420; - m_compute_width = (m_width * 420) / m_height; - m_camera.set_orbital_mode(true); - m_camera.set_radius(6.34194e10); - m_camera.set_min_radius(1e10); - m_camera.set_max_radius(1e12); - m_camera.set_orbit_speed(0.01f); + m_camera.set_camera_mode(CameraMode::Orbital); + m_camera.set_orbital_radius(6.34194e10); + m_camera.set_orbital_limits(1e10, 1e12); + m_camera.set_orbital_speed(0.01f); m_camera.set_zoom_speed(25e9f); m_objects = { - { glm::vec4(4e11f, 0.0f, 0.0f, 4e10f), glm::vec4(1,1,0,1), static_cast(1.98892e30) }, - { glm::vec4(0.0f, 0.0f, 4e11f, 4e10f), glm::vec4(1,0,0,1), static_cast(1.98892e30) }, - { glm::vec4(0.0f, 0.0f, 0.0f, m_sag_a.m_rs), glm::vec4(0,0,0,1), static_cast(m_sag_a.m_mass) } + { glm::vec4(4e11f, 0.00f, 0.00f, 4e10f), glm::vec4(1, 1, 0, 1), static_cast(1.98892e30) }, + { glm::vec4(0.00f, 0.00f, 4e11f, 4e10f), glm::vec4(1, 0, 0, 1), static_cast(1.98892e30) }, + { glm::vec4(0.00f, 0.00f, 0.00f, m_sag_a.m_rs), glm::vec4(0, 0, 0, 1), static_cast(m_sag_a.m_mass) } }; - m_quad_shader = Shader::create("assets/shaders/quad.glsl"); - m_grid_shader = Shader::create("assets/shaders/grid.glsl"); - m_compute_shader = Shader::create_compute("Geodesic", load_compute_shader("assets/shaders/geodesic.glsl")); + m_shader_program = Ref(Shader::create("assets/shaders/compute_texture_quad.glsl")); + m_compute_program = create_compute_program("assets/shaders/geodesic.glsl"); m_camera_ubo = UniformBuffer::create(128, 1); - m_disk_ubo = UniformBuffer::create(sizeof(float) * 4, 2); + m_disk_ubo = UniformBuffer::create(sizeof(float) * 4, 2); uint32_t obj_ubo_size = sizeof(int) + 3 * sizeof(float) + 16 * (sizeof(glm::vec4) + sizeof(glm::vec4)) + 16 * sizeof(float); m_objects_ubo = UniformBuffer::create(obj_ubo_size, 3); - float quad_vertices[] = - { - -1.0f, 1.0f, 0.0f, 1.0f, - -1.0f, -1.0f, 0.0f, 0.0f, - 1.0f, -1.0f, 1.0f, 0.0f, - - -1.0f, 1.0f, 0.0f, 1.0f, - 1.0f, -1.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 1.0f, 1.0f - }; - - m_quad_vao = VertexArray::create(); - - auto vertex_buffer = VertexBuffer::create(quad_vertices, static_cast(sizeof(quad_vertices))); - VertexBufferLayout layout; - layout.push(2); - layout.push(2); - vertex_buffer->set_layout(layout); - m_quad_vao->add_vertex_buffer(vertex_buffer); - - m_texture = Texture2D::create(m_width, m_height); + auto result = quad_vao(); + m_quad_vao = result.first; + m_texture = result.second; } - void Engine::generate_grid(const std::vector& objects) + void Engine::update_window_dimensions() { - const int grid_size = 25; - const float spacing = 1e10f; - - std::vector vertices; - std::vector indices; - - for (int z = 0; z <= grid_size; ++z) - { - for (int x = 0; x <= grid_size; ++x) - { - float world_x = (x - grid_size / 2) * spacing; - float world_z = (z - grid_size / 2) * spacing; - float y = 0.0f; - - for (const auto& obj : objects) - { - glm::vec3 obj_pos = glm::vec3(obj.m_pos_radius); - double mass = obj.m_mass; - double radius = obj.m_pos_radius.w; - - double r_s = 2.0 * G * mass / (c * c); - double dx = world_x - obj_pos.x; - double dz = world_z - obj_pos.z; - double dist = sqrt(dx * dx + dz * dz); - - if (dist > r_s) - { - double delta_y = 2.0 * sqrt(r_s * (dist - r_s)); - y += static_cast(delta_y) - 3e10f; - } - else - { - y += 2.0f * static_cast(sqrt(r_s * r_s)) - 3e10f; - } - } - - vertices.emplace_back(world_x, y, world_z); - } - } - - for (int z = 0; z < grid_size; ++z) - { - for (int x = 0; x < grid_size; ++x) - { - int i = z * (grid_size + 1) + x; - indices.push_back(i); - indices.push_back(i + 1); - indices.push_back(i); - indices.push_back(i + grid_size + 1); - } - } - - if (!m_grid_vao) - { - m_grid_vao = Ref(VertexArray::create()); - - auto vertex_buffer = Ref(VertexBuffer::create(vertices.data(), static_cast(vertices.size() * sizeof(glm::vec3)))); - VertexBufferLayout layout; - layout.push(3); - vertex_buffer->set_layout(layout); - m_grid_vao->add_vertex_buffer(vertex_buffer); - - auto index_buffer = Ref(IndexBuffer::create(indices.data(), static_cast(indices.size()))); - m_grid_vao->set_index_buffer(index_buffer); - } - else - { - auto vertex_buffer = m_grid_vao->get_vertex_buffers()[0]; - vertex_buffer->set_data(vertices.data(), static_cast(vertices.size() * sizeof(glm::vec3))); - } - - m_grid_index_count = static_cast(indices.size()); + GLFWwindow* window = static_cast(Application::get().get_window().get_native_window()); + int old_width = m_width; + int old_height = m_height; + int old_compute_height = m_compute_height; + + glfwGetFramebufferSize(window, &m_width, &m_height); + + if (old_width != m_width || + old_height != m_height || + old_compute_height != m_compute_height) + update_compute_dimensions(); } - void Engine::draw_grid(const glm::mat4& view_proj) + void Engine::update_performance(float delta_time) { - if (!m_grid_shader || !m_grid_vao) - return; - - m_grid_shader->bind(); - m_grid_shader->set_mat4("viewProj", view_proj); - - RenderCommand::disable_depth_test(); - RenderCommand::enable_blending(); - - m_grid_vao->bind(); - glDrawElements(GL_LINES, m_grid_index_count, GL_UNSIGNED_INT, nullptr); - - RenderCommand::enable_depth_test(); + if (delta_time > 0.0f) + m_current_fps = 1.0f / delta_time; } - void Engine::update_window_dimensions() + void Engine::update_compute_dimensions() { - GLFWwindow* window = static_cast(Application::get().get_window().get_native_window()); - int old_width = m_width; - int old_height = m_height; - glfwGetFramebufferSize(window, &m_width, &m_height); - m_compute_height = 420; - m_compute_width = (m_width * 420) / m_height; - - if (old_width != m_width || old_height != m_height) - m_texture = Texture2D::create(m_width, m_height); + m_texture = Texture2D::create(get_compute_width(), m_compute_height); } - void Engine::draw_full_screen_quad() + void Engine::draw_full_screen_quad() { RenderCommand::set_viewport(0, 0, m_width, m_height); - m_quad_shader->bind(); - std::cout << "Texture ID: " << m_texture->get_renderer_id() << ", Size: " << m_texture->get_width() << "x" << m_texture->get_height() << std::endl; + m_shader_program->bind(); + m_quad_vao->bind(); + m_texture->bind(0); - m_quad_shader->set_int("screenTexture", 0); - std::cout << "Set screenTexture uniform to slot 0\n"; + m_shader_program->set_int("u_ScreenTexture", 0); RenderCommand::disable_depth_test(); - RenderCommand::draw_indexed(m_quad_vao, 6); + RenderCommand::draw_arrays(6); RenderCommand::enable_depth_test(); } - void Engine::dispatch_compute(const Camera& cam) + void Engine::dispatch_compute(const Camera& cam) { - int cw = m_compute_width; + int cw = get_compute_width(); int ch = m_compute_height; - if (m_texture->get_width() != cw || m_texture->get_height() != ch) - m_texture = Texture2D::create(cw, ch); + m_texture->set_data(nullptr, cw * ch * 4); - m_compute_shader->bind(); + m_compute_program->bind(); upload_camera_ubo(cam); upload_disk_ubo(); upload_objects_ubo(m_objects); - m_texture->bind_as_image(0, false); - uint32_t groups_x = (uint32_t)std::ceil(cw / 16.0f); - uint32_t groups_y = (uint32_t)std::ceil(ch / 16.0f); - m_compute_shader->dispatch(groups_x, groups_y, 1); - m_compute_shader->memory_barrier(IMAGE_ACCESS_BARRIER_BIT); - - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); - glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); + uint32_t groups_x = static_cast(std::ceil(cw / 16.0f)); + uint32_t groups_y = static_cast(std::ceil(ch / 16.0f)); + m_compute_program->dispatch(groups_x, groups_y, 1); + m_compute_program->memory_barrier(IMAGE_ACCESS_BARRIER_BIT); } - void Engine::upload_camera_ubo(const Camera& cam) + void Engine::upload_camera_ubo(const Camera& cam) { - struct UBOData + struct UBOData { - glm::vec3 pos; float _pad0; - glm::vec3 right; float _pad1; - glm::vec3 up; float _pad2; + glm::vec3 pos; float _pad0; + glm::vec3 right; float _pad1; + glm::vec3 up; float _pad2; glm::vec3 forward; float _pad3; float tan_half_fov; float aspect; - bool moving; - int _pad4; + bool moving; + int _pad4; } data; - glm::vec3 fwd = glm::normalize(cam.get_target() - cam.get_orbital_position()); - glm::vec3 up = glm::vec3(0, 1, 0); + glm::vec3 fwd = glm::normalize(cam.get_orbital_target() - cam.get_orbital_position()); + glm::vec3 up = glm::vec3(0, 1, 0); glm::vec3 right = glm::normalize(glm::cross(fwd, up)); up = glm::cross(right, fwd); - data.pos = cam.get_orbital_position(); - data.right = right; - data.up = up; - data.forward = fwd; + data.pos = cam.get_orbital_position(); + data.right = right; + data.up = up; + data.forward = fwd; data.tan_half_fov = static_cast(tan(glm::radians(60.0f * 0.5f))); - data.aspect = static_cast(m_width) / static_cast(m_height); - data.moving = cam.is_dragging() || cam.is_panning(); + data.aspect = static_cast(get_compute_width()) / static_cast(m_compute_height); + data.moving = cam.is_dragging() || cam.is_panning(); m_camera_ubo->set_data(&data, sizeof(UBOData)); + m_camera_ubo->bind(1); } - void Engine::upload_objects_ubo(const std::vector& objs) + void Engine::upload_objects_ubo(const std::vector& objs) { - struct UBOData + struct UBOData { int num_objects; float _pad0, _pad1, _pad2; @@ -257,7 +150,7 @@ namespace Donut size_t count = std::min(objs.size(), size_t(16)); data.num_objects = static_cast(count); - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < count; ++i) { data.pos_radius[i] = objs[i].m_pos_radius; data.color[i] = objs[i].m_color; @@ -265,9 +158,10 @@ namespace Donut } m_objects_ubo->set_data(&data, sizeof(data)); + m_objects_ubo->bind(3); } - void Engine::upload_disk_ubo() + void Engine::upload_disk_ubo() { float r1 = static_cast(m_sag_a.m_rs * 2.2); float r2 = static_cast(m_sag_a.m_rs * 5.2); @@ -276,28 +170,28 @@ namespace Donut float disk_data[4] = { r1, r2, num, thickness }; m_disk_ubo->set_data(disk_data, sizeof(disk_data)); + m_disk_ubo->bind(2); } - void Engine::update_physics(float delta_time) + void Engine::update_physics(float delta_time) { - for (auto& obj : m_objects) + for (auto& obj : m_objects) { - for (auto& obj2 : m_objects) + for (auto& obj2 : m_objects) { if (&obj == &obj2) continue; float dx = obj2.m_pos_radius.x - obj.m_pos_radius.x; float dy = obj2.m_pos_radius.y - obj.m_pos_radius.y; float dz = obj2.m_pos_radius.z - obj.m_pos_radius.z; float distance = sqrt(dx * dx + dy * dy + dz * dz); - - if (distance > 0) + if (distance > 0) { std::vector direction = {dx / distance, dy / distance, dz / distance}; double Gforce = (G * obj.m_mass * obj2.m_mass) / (distance * distance); double acc1 = Gforce / obj.m_mass; std::vector acc = {direction[0] * acc1, direction[1] * acc1, direction[2] * acc1}; - - if (m_gravity) + + if (m_gravity) { obj.m_velocity.x += static_cast(acc[0]); obj.m_velocity.y += static_cast(acc[1]); @@ -314,34 +208,49 @@ namespace Donut void Engine::render_scene() { - glm::mat4 view = glm::lookAt(m_camera.get_orbital_position(), m_camera.get_target(), glm::vec3(0,1,0)); - glm::mat4 proj = glm::perspective(glm::radians(60.0f), float(m_width)/m_height, 1e9f, 1e14f); - glm::mat4 view_proj = proj * view; - - generate_grid(m_objects); - draw_grid(view_proj); - - RenderCommand::set_viewport(0, 0, m_width, m_height); - dispatch_compute(m_camera); - draw_full_screen_quad(); + RenderCommand::clear(); + m_shader_program->bind(); + m_quad_vao->bind(); + m_texture->bind(0); + RenderCommand::draw_arrays(6); } - std::string Engine::load_compute_shader(const std::string& path) + Ref Engine::create_compute_program(const char* path) { std::ifstream in(path); - if(!in.is_open()) + if(!in.is_open()) { std::cerr << "Failed to open compute shader: " << path << "\n"; - return ""; + return nullptr; } - std::stringstream ss; ss << in.rdbuf(); - std::string result = ss.str(); - if (result.empty()) - std::cerr << "Warning: Compute shader file is empty: " << path << "\n"; - else - std::cout << "Successfully loaded compute shader: " << path << " (size: " << result.size() << " bytes)\n"; - return result; + std::string src_str = ss.str(); + return Ref(Shader::create_compute("ComputeShader", src_str)); + } + + std::pair, Ref> Engine::quad_vao() + { + float quad_vertices[] = + { + -1.0f, 1.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + + auto vertex_buffer = Ref(VertexBuffer::create(quad_vertices, static_cast(sizeof(quad_vertices)))); + VertexBufferLayout layout; + layout.push(2); + layout.push(2); + vertex_buffer->set_layout(layout); + + auto vertex_array = Ref(VertexArray::create()); + vertex_array->add_vertex_buffer(vertex_buffer); + auto texture = Texture2D::create(get_compute_width(), m_compute_height); + + return { vertex_array, texture }; } } -- cgit v1.3