diff options
| author | hachem <im@hachem.wtf> | 2025-08-25 11:28:49 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2025-08-25 11:28:49 +0200 |
| commit | ecb6705c7fc4fb085184712567d0e936ea5d0d1f (patch) | |
| tree | 409937cd7fa094c36cf6607a88a2ef25913bdf18 | |
| parent | 12790572d039b8ea36d53013aa291d03a73ebe5c (diff) | |
fix: QOL improvements
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | assets/hdri/night_sky.hdr | bin | 0 -> 51708063 bytes | |||
| -rw-r--r-- | assets/shaders/equirect_to_cubemap.glsl | 30 | ||||
| -rw-r--r-- | assets/shaders/grid.glsl | 40 | ||||
| -rw-r--r-- | assets/shaders/textured_quad.glsl (renamed from assets/shaders/compute_texture_quad.glsl) | 0 | ||||
| -rw-r--r-- | src/core/hdri_manager.h | 3 | ||||
| -rw-r--r-- | src/engine/engine.cpp | 2 | ||||
| -rw-r--r-- | src/platform/opengl/opengl_texture.cpp | 6 | ||||
| -rw-r--r-- | src/states/world_builder_state.cpp | 160 | ||||
| -rw-r--r-- | src/states/world_builder_state.h | 18 |
10 files changed, 227 insertions, 33 deletions
@@ -48,6 +48,7 @@ Donut is a real-time black hole ray tracer that simulates the visual effects of - **Adaptive Performance**: Dynamic step size adjustment for optimal performance - **Multiple Objects**: Support for rendering stars and other celestial bodies - **Configurable Parameters**: Extensive settings for simulation and graphics +- **World Builder**: Interactive 3D scene editor with reference grid for spatial orientation ## System Requirements diff --git a/assets/hdri/night_sky.hdr b/assets/hdri/night_sky.hdr Binary files differnew file mode 100644 index 0000000..b473659 --- /dev/null +++ b/assets/hdri/night_sky.hdr diff --git a/assets/shaders/equirect_to_cubemap.glsl b/assets/shaders/equirect_to_cubemap.glsl index 2b99c9b..690706f 100644 --- a/assets/shaders/equirect_to_cubemap.glsl +++ b/assets/shaders/equirect_to_cubemap.glsl @@ -1,23 +1,29 @@ #type vertex #version 330 core -layout (location = 0) in vec3 aPos; -out vec3 WorldPos; -uniform mat4 projection; -uniform mat4 view; + +layout (location = 0) in vec3 a_Pos; +out vec3 v_WorldPos; + +uniform mat4 u_Projection; +uniform mat4 u_View; + void main() { - WorldPos = aPos; - gl_Position = projection * view * vec4(WorldPos, 1.0); + v_WorldPos = a_Pos; + gl_Position = u_Projection * u_View * vec4(v_WorldPos, 1.0); } #type fragment #version 330 core -out vec4 FragColor; -in vec3 WorldPos; -uniform sampler2D equirectangularMap; + +out vec4 o_FragColor; +in vec3 v_WorldPos; + +uniform sampler2D u_EquirectangularMap; const vec2 invAtan = vec2(0.1591, 0.3183); + vec2 SampleSphericalMap(vec3 v) { vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); @@ -27,7 +33,7 @@ vec2 SampleSphericalMap(vec3 v) } void main() { - vec2 uv = SampleSphericalMap(normalize(WorldPos)); - vec3 color = texture(equirectangularMap, uv).rgb; - FragColor = vec4(color, 1.0); + vec2 uv = SampleSphericalMap(normalize(v_WorldPos)); + vec3 color = texture(u_EquirectangularMap, uv).rgb; + o_FragColor = vec4(color, 1.0); } diff --git a/assets/shaders/grid.glsl b/assets/shaders/grid.glsl new file mode 100644 index 0000000..81523b3 --- /dev/null +++ b/assets/shaders/grid.glsl @@ -0,0 +1,40 @@ +#type vertex + +#version 330 core + +layout(location = 0) in vec3 a_Position; + +uniform mat4 u_ViewProjection; +uniform mat4 u_Transform; +uniform float u_GridSize; + +void main() +{ + vec3 scaledPosition = a_Position * (u_GridSize / 50.0); + gl_Position = u_ViewProjection * u_Transform * vec4(scaledPosition, 1.0); +} + +#type fragment + +#version 330 core + +uniform vec3 u_GridColor; +uniform float u_GridAlpha; +uniform float u_GridSize; +uniform vec3 u_CameraPos; + +out vec4 o_FragColor; + +void main() +{ + float distance = length(u_CameraPos); + float fadeFactor = 1.0 - clamp(distance / 100.0, 0.0, 0.8); + + vec3 color = u_GridColor; + float alpha = u_GridAlpha * fadeFactor; + + float gridFade = 1.0 - clamp(distance / 50.0, 0.0, 0.9); + alpha *= gridFade; + + o_FragColor = vec4(color, alpha); +} diff --git a/assets/shaders/compute_texture_quad.glsl b/assets/shaders/textured_quad.glsl index 95f433d..95f433d 100644 --- a/assets/shaders/compute_texture_quad.glsl +++ b/assets/shaders/textured_quad.glsl diff --git a/src/core/hdri_manager.h b/src/core/hdri_manager.h index 5ccd402..3bdf1cb 100644 --- a/src/core/hdri_manager.h +++ b/src/core/hdri_manager.h @@ -40,7 +40,8 @@ namespace Donut { "assets/hdri/hdr_blue_nebulae_1.hdr", "assets/hdri/hdr_subdued_blue_nebulae.hdr", - "assets/hdri/hdr_subdued_multi_nebulae.hdr" + "assets/hdri/hdr_subdued_multi_nebulae.hdr", + "assets/hdri/night_sky.hdr" }; }; }; diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 451684b..28cce2f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -33,8 +33,8 @@ namespace Donut { glm::vec4(0.00f, 0.00f, 0.00f, m_sag_a.m_rs), glm::vec4(0, 0, 0, 1), static_cast<float>(m_sag_a.m_mass) } }; - m_shader_program = Ref<Shader>(Shader::create("assets/shaders/compute_texture_quad.glsl")); m_compute_program = create_compute_program("assets/shaders/geodesic.glsl"); + m_shader_program = Ref<Shader>(Shader::create("assets/shaders/textured_quad.glsl")); m_blur_shader = Ref<Shader>(Shader::create("assets/shaders/blur.glsl")); auto& hdri_manager = HDRIManager::get(); diff --git a/src/platform/opengl/opengl_texture.cpp b/src/platform/opengl/opengl_texture.cpp index 14ae214..34a5117 100644 --- a/src/platform/opengl/opengl_texture.cpp +++ b/src/platform/opengl/opengl_texture.cpp @@ -208,8 +208,8 @@ namespace Donut }; glUseProgram(shader_program); - glUniform1i(glGetUniformLocation(shader_program, "equirectangularMap"), 0); - glUniformMatrix4fv(glGetUniformLocation(shader_program, "projection"), 1, GL_FALSE, &capture_projection[0][0]); + glUniform1i(glGetUniformLocation(shader_program, "u_EquirectangularMap"), 0); + glUniformMatrix4fv(glGetUniformLocation(shader_program, "u_Projection"), 1, GL_FALSE, &capture_projection[0][0]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, hdr_texture); @@ -217,7 +217,7 @@ namespace Donut glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo); for (unsigned int i = 0; i < 6; ++i) { - glUniformMatrix4fv(glGetUniformLocation(shader_program, "view"), 1, GL_FALSE, &capture_views[i][0][0]); + glUniformMatrix4fv(glGetUniformLocation(shader_program, "u_View"), 1, GL_FALSE, &capture_views[i][0][0]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, m_renderer_id, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindVertexArray(cube_vao); diff --git a/src/states/world_builder_state.cpp b/src/states/world_builder_state.cpp index c0999d4..ab3e2b3 100644 --- a/src/states/world_builder_state.cpp +++ b/src/states/world_builder_state.cpp @@ -46,14 +46,18 @@ namespace Donut m_sphere_shader = Ref<Shader>(Shader::create("assets/shaders/sphere.glsl")); m_skybox_shader = Ref<Shader>(Shader::create("assets/shaders/skybox.glsl")); + m_grid_shader = Ref<Shader>(Shader::create("assets/shaders/grid.glsl")); if (!m_sphere_shader) DONUT_ERROR("Failed to create sphere shader"); if (!m_skybox_shader) DONUT_ERROR("Failed to create skybox shader"); + if (!m_grid_shader) + DONUT_ERROR("Failed to create grid shader"); initialize_sphere_geometry(); initialize_skybox_geometry(); + initialize_grid_geometry(); auto& hdri_manager = HDRIManager::get(); m_hdri_environment = hdri_manager.get_current_hdri(); @@ -69,6 +73,8 @@ namespace Donut m_black_hole = Object(glm::vec3(0.0f, 0.0f, 0.0f), 2.0f, black_hole_material); m_black_hole_initialized = true; + m_grid_size = 10.0f; + m_initialized = true; } @@ -117,6 +123,9 @@ namespace Donut if (m_hdri_environment) render_skybox(); + if (m_show_grid) + render_grid(); + render_scene(); } @@ -285,13 +294,13 @@ namespace Donut { switch (e.get_key_code()) { - case GLFW_KEY_W: + case GLFW_KEY_M: m_gizmo_operation = ImGuizmo::TRANSLATE; return true; - case GLFW_KEY_E: + case GLFW_KEY_R: m_gizmo_operation = ImGuizmo::ROTATE; return true; - case GLFW_KEY_R: + case GLFW_KEY_S: m_gizmo_operation = ImGuizmo::SCALE; return true; } @@ -319,7 +328,7 @@ namespace Donut ImGui::PopFont(); ImGui::Separator(); - if (ImGui::CollapsingHeader("Scene Info", &m_show_scene_info)) + if (ImGui::CollapsingHeader("Scene Info")) { ImGui::Text("Objects in scene: %zu/16 (+ 1 black hole)", m_scene.objs.size()); @@ -367,7 +376,7 @@ namespace Donut ImGui::Spacing(); - if (ImGui::CollapsingHeader("Create Object", &m_show_object_creator)) + if (ImGui::CollapsingHeader("Create Object")) { ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "New Sphere"); ImGui::Separator(); @@ -406,7 +415,7 @@ namespace Donut ImGui::Spacing(); - if (ImGui::CollapsingHeader("Scene Objects", &m_show_object_list)) + if (ImGui::CollapsingHeader("Scene Objects")) { if (m_black_hole_initialized) { @@ -458,7 +467,7 @@ namespace Donut ImGui::Spacing(); - if (ImGui::CollapsingHeader("Gizmo Controls", &m_show_gizmo_controls)) + if (ImGui::CollapsingHeader("Gizmo Controls")) { ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Gizmo Operation:"); @@ -473,12 +482,12 @@ namespace Donut ImGui::Spacing(); ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Hotkeys:"); - ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "W = Translate, E = Rotate, R = Scale"); + ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "M = Move, R = Rotate, S = Scale"); } ImGui::Spacing(); - if (ImGui::CollapsingHeader("Selection Outline", &m_show_outline_controls)) + if (ImGui::CollapsingHeader("Selection Outline")) { ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Outline Settings:"); @@ -494,6 +503,33 @@ namespace Donut ImGui::Spacing(); + if (ImGui::CollapsingHeader("Grid Settings")) + { + ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Grid Settings:"); + + ImGui::Text("Show Grid:"); + ImGui::SameLine(); + ImGui::Checkbox("##ShowGrid", &m_show_grid); + + ImGui::Text("Grid Color:"); + ImGui::ColorEdit3("##GridColor", &m_grid_color.x); + + ImGui::Text("Grid Alpha:"); + ImGui::SliderFloat("##GridAlpha", &m_grid_alpha, 0.0f, 1.0f, "%.2f"); + + ImGui::Text("Grid Size:"); + ImGui::SliderFloat("##GridSize", &m_grid_size, 1.0f, 500.0f, "%.1f"); + + ImGui::Spacing(); + if (ImGui::Button("Regenerate Grid", ImVec2(ImGui::GetWindowWidth() - 20, 25))) + initialize_grid_geometry(); + + ImGui::Spacing(); + ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "Reference grid for spatial orientation"); + } + + ImGui::Spacing(); + if (ImGui::CollapsingHeader("HDRI Environment", nullptr)) { ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "HDRI Settings:"); @@ -560,7 +596,7 @@ namespace Donut ImGui::Spacing(); ImGui::Separator(); ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Camera: Left mouse = rotate, Scroll = zoom"); - ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Gizmo: W=Translate, E=Rotate, R=Scale"); + ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Gizmo: M=Move, R=Rotate, S=Scale"); ImGui::End(); @@ -943,9 +979,7 @@ namespace Donut void WorldBuilderState::render_skybox() { if (!m_skybox_shader || !m_skybox_vao || !m_hdri_environment) - { return; - } GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); int width, height; @@ -971,4 +1005,106 @@ namespace Donut RenderCommand::enable_depth_test(); } + + void WorldBuilderState::initialize_grid_geometry() + { + if (m_grid_vao) + { + m_grid_vao->unbind(); + m_grid_vao.reset(); + } + + const float grid_size = 50.0f; + const int grid_lines = 101; + const float half_size = grid_size * 0.5f; + const float step = grid_size / (grid_lines - 1); + + std::vector<float> vertices; + std::vector<uint32_t> indices; + + for (int i = 0; i < grid_lines; ++i) + { + float z = -half_size + i * step; + + vertices.push_back(-half_size); + vertices.push_back(0.0f); + vertices.push_back(z); + + vertices.push_back(half_size); + vertices.push_back(0.0f); + vertices.push_back(z); + + uint32_t base_index = static_cast<uint32_t>(vertices.size() / 3) - 2; + indices.push_back(base_index); + indices.push_back(base_index + 1); + } + + for (int i = 0; i < grid_lines; ++i) + { + float x = -half_size + i * step; + + vertices.push_back(x); + vertices.push_back(0.0f); + vertices.push_back(-half_size); + + vertices.push_back(x); + vertices.push_back(0.0f); + vertices.push_back(half_size); + + uint32_t base_index = static_cast<uint32_t>(vertices.size() / 3) - 2; + indices.push_back(base_index); + indices.push_back(base_index + 1); + } + + auto vertex_buffer = Ref<VertexBuffer>(VertexBuffer::create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(float)))); + VertexBufferLayout layout; + layout.push<float>(3); + vertex_buffer->set_layout(layout); + + auto index_buffer = Ref<IndexBuffer>(IndexBuffer::create(indices.data(), static_cast<uint32_t>(indices.size()))); + + m_grid_vao = Ref<VertexArray>(VertexArray::create()); + m_grid_vao->add_vertex_buffer(vertex_buffer); + m_grid_vao->set_index_buffer(index_buffer); + + m_grid_vao->unbind(); + } + + void WorldBuilderState::render_grid() + { + if (!m_grid_shader || !m_grid_vao) + return; + + GLFWwindow* window = static_cast<GLFWwindow*>(Application::get().get_window().get_native_window()); + int width, height; + glfwGetFramebufferSize(window, &width, &height); + + RenderCommand::set_viewport(0, 0, width, height); + RenderCommand::enable_depth_test(); + RenderCommand::enable_blending(); + + glm::mat4 view = m_camera.get_view_matrix(); + glm::mat4 projection = m_camera.get_projection_matrix(); + glm::mat4 view_projection = projection * view; + glm::mat4 transform = glm::mat4(1.0f); + + glm::vec3 camera_pos = m_camera.get_orbital_position(); + + m_grid_shader->bind(); + m_grid_shader->set_mat4("u_ViewProjection", view_projection); + m_grid_shader->set_mat4("u_Transform", transform); + m_grid_shader->set_float3("u_GridColor", m_grid_color); + m_grid_shader->set_float("u_GridAlpha", m_grid_alpha); + m_grid_shader->set_float("u_GridSize", m_grid_size); + m_grid_shader->set_float3("u_CameraPos", camera_pos); + + m_grid_vao->bind(); + RenderCommand::draw_lines(m_grid_vao); + + m_grid_vao->unbind(); + m_grid_shader->unbind(); + RenderCommand::disable_blending(); + + RenderCommand::enable_depth_test(); + } }; diff --git a/src/states/world_builder_state.h b/src/states/world_builder_state.h index edfb346..243b750 100644 --- a/src/states/world_builder_state.h +++ b/src/states/world_builder_state.h @@ -40,6 +40,8 @@ namespace Donut void load_scene(); void render_scene(); void initialize_sphere_geometry(); + void initialize_grid_geometry(); + void render_grid(); private: Scene m_scene; Camera m_camera; @@ -52,6 +54,9 @@ namespace Donut Ref<Shader> m_skybox_shader; Ref<VertexArray> m_skybox_vao; + Ref<Shader> m_grid_shader; + Ref<VertexArray> m_grid_vao; + glm::vec3 m_new_object_position = glm::vec3(0.0f, 0.0f, 0.0f); float m_new_object_radius = 1.0f; glm::vec3 m_new_object_color = glm::vec3(1.0f, 1.0f, 1.0f); @@ -65,15 +70,20 @@ namespace Donut ImGuizmo::OPERATION m_gizmo_operation = ImGuizmo::TRANSLATE; ImGuizmo::MODE m_gizmo_mode = ImGuizmo::LOCAL; - bool m_show_object_list = true; - bool m_show_object_creator = true; - bool m_show_scene_info = true; - bool m_show_gizmo_controls = true; + bool m_show_object_list = true; + bool m_show_object_creator = true; + bool m_show_scene_info = true; + bool m_show_gizmo_controls = true; bool m_show_outline_controls = true; + bool m_show_grid = true; glm::vec3 m_outline_color = glm::vec3(1.0f, 1.0f, 1.0f); float m_outline_width = 0.25f; + glm::vec3 m_grid_color = glm::vec3(0.5f, 0.5f, 0.5f); + float m_grid_alpha = 0.5f; + float m_grid_size = 50.0f; + Object m_black_hole; bool m_black_hole_initialized = false; |
