diff options
| -rw-r--r-- | Assets/HDRI/night_sky.hdr | bin | 0 -> 51708063 bytes | |||
| -rw-r--r-- | Assets/Shaders/EquirectToCubemap.glsl | 30 | ||||
| -rw-r--r-- | Assets/Shaders/Grid.glsl | 41 | ||||
| -rw-r--r-- | Assets/Shaders/TexturedQuad.glsl (renamed from Assets/Shaders/ComputeTextureQuad.glsl) | 0 | ||||
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | src/Core/HDRIManager.h | 3 | ||||
| -rw-r--r-- | src/Engine/Engine.cpp | 2 | ||||
| -rw-r--r-- | src/Platform/OpenGL/OpenGLTexture.cpp | 6 | ||||
| -rw-r--r-- | src/States/WorldBuilderState.cpp | 163 | ||||
| -rw-r--r-- | src/States/WorldBuilderState.h | 18 |
10 files changed, 231 insertions, 33 deletions
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/EquirectToCubemap.glsl b/Assets/Shaders/EquirectToCubemap.glsl index 2b99c9b..690706f 100644 --- a/Assets/Shaders/EquirectToCubemap.glsl +++ b/Assets/Shaders/EquirectToCubemap.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..32c091a --- /dev/null +++ b/Assets/Shaders/Grid.glsl @@ -0,0 +1,41 @@ +#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() +{ + // Scale the grid based on the grid size uniform + 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/ComputeTextureQuad.glsl b/Assets/Shaders/TexturedQuad.glsl index 95f433d..95f433d 100644 --- a/Assets/Shaders/ComputeTextureQuad.glsl +++ b/Assets/Shaders/TexturedQuad.glsl @@ -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/src/Core/HDRIManager.h b/src/Core/HDRIManager.h index ebefb3a..3c1ff57 100644 --- a/src/Core/HDRIManager.h +++ b/src/Core/HDRIManager.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 a947357..453dce9 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_SagA.m_Rs), glm::vec4(0, 0, 0, 1), static_cast<float>(m_SagA.m_Mass) } }; - m_ShaderProgram = Ref<Shader>(Shader::Create("Assets/Shaders/ComputeTextureQuad.glsl")); m_ComputeProgram = CreateComputeProgram("Assets/Shaders/Geodesic.glsl"); + m_ShaderProgram = Ref<Shader>(Shader::Create("Assets/Shaders/TexturedQuad.glsl")); m_BlurShader = Ref<Shader>(Shader::Create("Assets/Shaders/Blur.glsl")); auto& hdriManager = HDRIManager::Get(); diff --git a/src/Platform/OpenGL/OpenGLTexture.cpp b/src/Platform/OpenGL/OpenGLTexture.cpp index d9033dc..ef5bdaa 100644 --- a/src/Platform/OpenGL/OpenGLTexture.cpp +++ b/src/Platform/OpenGL/OpenGLTexture.cpp @@ -208,8 +208,8 @@ namespace Donut }; glUseProgram(shaderProgram); - glUniform1i(glGetUniformLocation(shaderProgram, "equirectangularMap"), 0); - glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, &captureProjection[0][0]); + glUniform1i(glGetUniformLocation(shaderProgram, "u_EquirectangularMap"), 0); + glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_Projection"), 1, GL_FALSE, &captureProjection[0][0]); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, hdrTexture); @@ -217,7 +217,7 @@ namespace Donut glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); for (unsigned int i = 0; i < 6; ++i) { - glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, &captureViews[i][0][0]); + glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_View"), 1, GL_FALSE, &captureViews[i][0][0]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, m_RendererID, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindVertexArray(cubeVAO); diff --git a/src/States/WorldBuilderState.cpp b/src/States/WorldBuilderState.cpp index 5a27ea1..3c49f62 100644 --- a/src/States/WorldBuilderState.cpp +++ b/src/States/WorldBuilderState.cpp @@ -46,14 +46,18 @@ namespace Donut m_SphereShader = Ref<Shader>(Shader::Create("Assets/Shaders/Sphere.glsl")); m_SkyboxShader = Ref<Shader>(Shader::Create("Assets/Shaders/Skybox.glsl")); + m_GridShader = Ref<Shader>(Shader::Create("Assets/Shaders/Grid.glsl")); if (!m_SphereShader) DONUT_ERROR("Failed to create sphere shader"); if (!m_SkyboxShader) DONUT_ERROR("Failed to create skybox shader"); + if (!m_GridShader) + DONUT_ERROR("Failed to create grid shader"); InitializeSphereGeometry(); InitializeSkyboxGeometry(); + InitializeGridGeometry(); auto& hdriManager = HDRIManager::Get(); m_HDRIEnvironment = hdriManager.GetCurrentHDRI(); @@ -69,6 +73,9 @@ namespace Donut m_BlackHole = Object(glm::vec3(0.0f, 0.0f, 0.0f), 2.0f, blackHoleMaterial); m_BlackHoleInitialized = true; + // Set default grid size + m_GridSize = 10.0f; + m_Initialized = true; } @@ -117,6 +124,9 @@ namespace Donut if (m_HDRIEnvironment) RenderSkybox(); + if (m_ShowGrid) + RenderGrid(); + RenderScene(); } @@ -285,13 +295,13 @@ namespace Donut { switch (e.GetKeyCode()) { - case GLFW_KEY_W: + case GLFW_KEY_M: m_GizmoOperation = ImGuizmo::TRANSLATE; return true; - case GLFW_KEY_E: + case GLFW_KEY_R: m_GizmoOperation = ImGuizmo::ROTATE; return true; - case GLFW_KEY_R: + case GLFW_KEY_S: m_GizmoOperation = ImGuizmo::SCALE; return true; } @@ -319,7 +329,7 @@ namespace Donut ImGui::PopFont(); ImGui::Separator(); - if (ImGui::CollapsingHeader("Scene Info", &m_ShowSceneInfo)) + if (ImGui::CollapsingHeader("Scene Info")) { ImGui::Text("Objects in scene: %zu/16 (+ 1 black hole)", m_Scene.objs.size()); @@ -367,7 +377,7 @@ namespace Donut ImGui::Spacing(); - if (ImGui::CollapsingHeader("Create Object", &m_ShowObjectCreator)) + if (ImGui::CollapsingHeader("Create Object")) { ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "New Sphere"); ImGui::Separator(); @@ -406,7 +416,7 @@ namespace Donut ImGui::Spacing(); - if (ImGui::CollapsingHeader("Scene Objects", &m_ShowObjectList)) + if (ImGui::CollapsingHeader("Scene Objects")) { if (m_BlackHoleInitialized) { @@ -458,7 +468,7 @@ namespace Donut ImGui::Spacing(); - if (ImGui::CollapsingHeader("Gizmo Controls", &m_ShowGizmoControls)) + if (ImGui::CollapsingHeader("Gizmo Controls")) { ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Gizmo Operation:"); @@ -473,12 +483,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_ShowOutlineControls)) + if (ImGui::CollapsingHeader("Selection Outline")) { ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Outline Settings:"); @@ -494,6 +504,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_ShowGrid); + + ImGui::Text("Grid Color:"); + ImGui::ColorEdit3("##GridColor", &m_GridColor.x); + + ImGui::Text("Grid Alpha:"); + ImGui::SliderFloat("##GridAlpha", &m_GridAlpha, 0.0f, 1.0f, "%.2f"); + + ImGui::Text("Grid Size:"); + ImGui::SliderFloat("##GridSize", &m_GridSize, 1.0f, 500.0f, "%.1f"); + + ImGui::Spacing(); + if (ImGui::Button("Regenerate Grid", ImVec2(ImGui::GetWindowWidth() - 20, 25))) + InitializeGridGeometry(); + + 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 +597,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 +980,7 @@ namespace Donut void WorldBuilderState::RenderSkybox() { if (!m_SkyboxShader || !m_SkyboxVAO || !m_HDRIEnvironment) - { return; - } GLFWwindow* window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow()); int width, height; @@ -971,4 +1006,108 @@ namespace Donut RenderCommand::EnableDepthTest(); } + + void WorldBuilderState::InitializeGridGeometry() + { + if (m_GridVAO) + { + m_GridVAO->Unbind(); + m_GridVAO.reset(); + } + + const float gridSize = 50.0f; + const int gridLines = 101; + const float halfSize = gridSize * 0.5f; + const float step = gridSize / (gridLines - 1); + + std::vector<float> vertices; + std::vector<uint32_t> indices; + + for (int i = 0; i < gridLines; ++i) + { + float z = -halfSize + i * step; + + vertices.push_back(-halfSize); + vertices.push_back(0.0f); + vertices.push_back(z); + + vertices.push_back(halfSize); + vertices.push_back(0.0f); + vertices.push_back(z); + + uint32_t baseIndex = static_cast<uint32_t>(vertices.size() / 3) - 2; + indices.push_back(baseIndex); + indices.push_back(baseIndex + 1); + } + + for (int i = 0; i < gridLines; ++i) + { + float x = -halfSize + i * step; + + vertices.push_back(x); + vertices.push_back(0.0f); + vertices.push_back(-halfSize); + + vertices.push_back(x); + vertices.push_back(0.0f); + vertices.push_back(halfSize); + + uint32_t baseIndex = static_cast<uint32_t>(vertices.size() / 3) - 2; + indices.push_back(baseIndex); + indices.push_back(baseIndex + 1); + } + + auto vertexBuffer = Ref<VertexBuffer>(VertexBuffer::Create(vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(float)))); + VertexBufferLayout layout; + layout.Push<float>(3); + vertexBuffer->SetLayout(layout); + + auto indexBuffer = Ref<IndexBuffer>(IndexBuffer::Create(indices.data(), static_cast<uint32_t>(indices.size()))); + + m_GridVAO = Ref<VertexArray>(VertexArray::Create()); + m_GridVAO->AddVertexBuffer(vertexBuffer); + m_GridVAO->SetIndexBuffer(indexBuffer); + + m_GridVAO->Unbind(); + } + + void WorldBuilderState::RenderGrid() + { + if (!m_GridShader || !m_GridVAO) + return; + + GLFWwindow* window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow()); + int width, height; + glfwGetFramebufferSize(window, &width, &height); + + RenderCommand::SetViewport(0, 0, width, height); + RenderCommand::EnableDepthTest(); + RenderCommand::EnableBlending(); + + glm::mat4 view = m_Camera.GetViewMatrix(); + glm::mat4 projection = m_Camera.GetProjectionMatrix(); + glm::mat4 viewProjection = projection * view; + glm::mat4 transform = glm::mat4(1.0f); + + glm::vec3 cameraPos = m_Camera.GetOrbitalPosition(); + + m_GridShader->Bind(); + m_GridShader->SetMat4("u_ViewProjection", viewProjection); + m_GridShader->SetMat4("u_Transform", transform); + m_GridShader->SetFloat3("u_GridColor", m_GridColor); + m_GridShader->SetFloat("u_GridAlpha", m_GridAlpha); + m_GridShader->SetFloat("u_GridSize", m_GridSize); + m_GridShader->SetFloat3("u_CameraPos", cameraPos); + + m_GridVAO->Bind(); + RenderCommand::DrawLines(m_GridVAO); + + // Clean up state to prevent conflicts with scene rendering + m_GridVAO->Unbind(); + m_GridShader->Unbind(); + RenderCommand::DisableBlending(); + + // Ensure depth test is still enabled for scene rendering + RenderCommand::EnableDepthTest(); + } }; diff --git a/src/States/WorldBuilderState.h b/src/States/WorldBuilderState.h index 29662db..2d65060 100644 --- a/src/States/WorldBuilderState.h +++ b/src/States/WorldBuilderState.h @@ -40,6 +40,8 @@ namespace Donut void LoadScene(); void RenderScene(); void InitializeSphereGeometry(); + void InitializeGridGeometry(); + void RenderGrid(); private: Scene m_Scene; Camera m_Camera; @@ -52,6 +54,9 @@ namespace Donut Ref<Shader> m_SkyboxShader; Ref<VertexArray> m_SkyboxVAO; + Ref<Shader> m_GridShader; + Ref<VertexArray> m_GridVAO; + glm::vec3 m_NewObjectPosition = glm::vec3(0.0f, 0.0f, 0.0f); float m_NewObjectRadius = 1.0f; glm::vec3 m_NewObjectColor = glm::vec3(1.0f, 1.0f, 1.0f); @@ -65,15 +70,20 @@ namespace Donut ImGuizmo::OPERATION m_GizmoOperation = ImGuizmo::TRANSLATE; ImGuizmo::MODE m_GizmoMode = ImGuizmo::LOCAL; - bool m_ShowObjectList = true; - bool m_ShowObjectCreator = true; - bool m_ShowSceneInfo = true; - bool m_ShowGizmoControls = true; + bool m_ShowObjectList = true; + bool m_ShowObjectCreator = true; + bool m_ShowSceneInfo = true; + bool m_ShowGizmoControls = true; bool m_ShowOutlineControls = true; + bool m_ShowGrid = true; glm::vec3 m_OutlineColor = glm::vec3(1.0f, 1.0f, 1.0f); float m_OutlineWidth = 0.25f; + glm::vec3 m_GridColor = glm::vec3(0.5f, 0.5f, 0.5f); + float m_GridAlpha = 0.5f; + float m_GridSize = 50.0f; + Object m_BlackHole; bool m_BlackHoleInitialized = false; |
