diff --git a/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp b/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp index 9c7f101a..42221b73 100644 --- a/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp +++ b/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp @@ -48,7 +48,8 @@ void ViewportWidget::Draw() // This is important for make UI mouse coord relative to viewport // Nuake::Input::SetViewportDimensions(m_ViewportPos, viewportPanelSize); - VkDescriptorSet textureDesc = VkRenderer::Get().DrawImage->GetImGuiDescriptorSet(); + VkDescriptorSet textureDesc = sceneViewport->GetRenderTarget()->GetImGuiDescriptorSet(); + //VkDescriptorSet textureDesc = VkRenderer::Get().DrawImage->GetImGuiDescriptorSet(); ImVec2 imagePos = ImGui::GetWindowPos() + ImGui::GetCursorPos(); // Input::SetEditorViewportSize(m_ViewportPos, viewportPanelSize); diff --git a/Nuake/src/Rendering/Vulkan/RenderContext.h b/Nuake/src/Rendering/Vulkan/RenderContext.h index d68e1abf..cc103ee8 100644 --- a/Nuake/src/Rendering/Vulkan/RenderContext.h +++ b/Nuake/src/Rendering/Vulkan/RenderContext.h @@ -8,6 +8,7 @@ namespace Nuake { class Scene; + class VulkanImage; struct RenderContext { @@ -15,6 +16,7 @@ namespace Nuake Cmd CommandBuffer; // The command buffer we are recording into Vector2 Size; UUID CameraID; + Ref ViewportImage; // We might add more to this! }; } \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/SceneViewport.cpp b/Nuake/src/Rendering/Vulkan/SceneViewport.cpp index b5d118bb..c58ee745 100644 --- a/Nuake/src/Rendering/Vulkan/SceneViewport.cpp +++ b/Nuake/src/Rendering/Vulkan/SceneViewport.cpp @@ -10,6 +10,6 @@ Viewport::Viewport(UUID inViewId, const Vector2& inViewportSize) : viewId(inViewId) { // Create render target - renderTarget = CreateRef(ImageFormat::RGBA8, viewportSize); + renderTarget = CreateRef(ImageFormat::RGBA16F, viewportSize); } diff --git a/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp index 218401f0..a757546a 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp @@ -391,6 +391,7 @@ void VkRenderer::DrawScenes() ctx.CameraID = viewport->GetViewID(); ctx.Size = viewport->GetViewportSize(); + ctx.ViewportImage = viewport->GetRenderTarget(); SceneRenderer->DrawSceneView(ctx); } } @@ -686,6 +687,11 @@ bool VkRenderer::Draw() VK_CALL(vkBeginCommandBuffer(cmd, &cmdBeginInfo)); // Transfer rendering image to general layout + for (auto& [_id, viewport] : Viewports) + { + viewport->GetRenderTarget()->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); + } + DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); //VulkanUtil::TransitionImage(cmd, DrawImage->GetImage(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); @@ -717,12 +723,21 @@ void VkRenderer::EndDraw() VulkanUtil::TransitionImage(cmd, SwapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + for (auto& [_id, viewport] : Viewports) + { + viewport->GetRenderTarget()->TransitionLayout(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + // VulkanUtil::TransitionImage(cmd, DrawImage->GetImage(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); DrawImgui(cmd, SwapchainImageViews[swapchainImageIndex]); // Transition the swapchain image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR for presentation VulkanUtil::TransitionImage(cmd, SwapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); DrawImage->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); + for (auto& [_id, viewport] : Viewports) + { + viewport->GetRenderTarget()->TransitionLayout(cmd, VK_IMAGE_LAYOUT_GENERAL); + } VK_CALL(vkEndCommandBuffer(cmd)); VkCommandBufferSubmitInfo cmdinfo = VulkanInit::CommandBufferSubmitInfo(cmd); diff --git a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp index 38587653..309d92a0 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanSceneRenderer.cpp @@ -140,6 +140,80 @@ void VkSceneRenderer::PrepareScenes(const std::vector>& scenes, Rende } // Models + { + uint32_t currentIndex = 0; + uint32_t currentMaterialIndex = 0; + std::array allTransforms; + std::array allMaterials; + auto view = scene->m_Registry.view(); + for (auto e : view) + { + // Check if we've reached the maximum capacity of the array + if (currentIndex >= MAX_MODEL_MATRIX) + { + assert(false && "Max model matrix reached!"); + break; + } + + auto [transform, mesh, visibility] = view.get(e); + + // Get() will load the resource if its not loaded already + Ref modelResource = mesh.ModelResource.Get(); + if (!modelResource || !visibility.Visible) + { + continue; + } + + // Upload transforms to GPU resources + allTransforms[currentIndex] = transform.GetGlobalTransform(); + gpu.ModelMatrixMapping[Entity((entt::entity)e, scene.get()).GetID()] = currentIndex; + + // Upload mesh material to GPU resources + for (auto& m : modelResource->GetMeshes()) + { + // TODO: Avoid duplicated materials + Ref material = m->GetMaterial(); + if (!material) + { + // insert missing material. + static Ref missingMaterial = CreateRef(); + missingMaterial->AlbedoImage = TextureManager::Get()->GetTexture2("missing_texture")->GetID(); + + material = missingMaterial; + } + + MaterialBufferStruct materialBuffer + { + .HasAlbedo = material->HasAlbedo(), + .AlbedoColor = material->data.m_AlbedoColor, + .HasNormal = material->HasNormal(), + .HasMetalness = material->HasMetalness(), + .HasRoughness = material->HasRoughness(), + .HasAO = material->HasAO(), + .MetalnessValue = material->data.u_MetalnessValue, + .RoughnessValue = material->data.u_RoughnessValue, + .AoValue = material->data.u_AOValue, + .AlbedoTextureId = material->HasAlbedo() ? gpu.GetBindlessTextureID(material->AlbedoImage) : 0, + .NormalTextureId = material->HasNormal() ? gpu.GetBindlessTextureID(material->NormalImage) : 0, + .MetalnessTextureId = material->HasMetalness() ? gpu.GetBindlessTextureID(material->MetalnessImage) : 0, + .RoughnessTextureId = material->HasRoughness() ? gpu.GetBindlessTextureID(material->RoughnessImage) : 0, + .AoTextureId = material->HasAO() ? gpu.GetBindlessTextureID(material->AOImage) : 0, + }; + + // Save bindless mapping index + allMaterials[currentMaterialIndex] = std::move(materialBuffer); + gpu.MeshMaterialMapping[m->GetVkMesh()->GetID()] = currentMaterialIndex; + currentMaterialIndex++; + } + + currentIndex++; + } + + gpu.ModelTransforms = ModelData{ allTransforms }; + gpu.MaterialDataContainer = MaterialData{ allMaterials }; + } + + // Lights { uint32_t lightCount = 0; std::array allLights; @@ -205,49 +279,57 @@ void VkSceneRenderer::PrepareScenes(const std::vector>& scenes, Rende } } } - } - gpu.RecreateBindlessCameras(); + gpu.RecreateBindlessCameras(); - for (auto& scene : scenes) - { - - PassRenderContext passCtx = { }; - passCtx.scene = scene; - passCtx.commandBuffer = inContext.CommandBuffer; - passCtx.resolution = Context.Size; - passCtx.cameraID = GPUResources::Get().GetBindlessCameraID(inContext.CameraID); - - auto view = scene->m_Registry.view(); - for (auto e : view) + for (auto& scene : scenes) { - auto [transform, light] = view.get(e); + PassRenderContext passCtx = { }; + passCtx.scene = scene; + passCtx.commandBuffer = inContext.CommandBuffer; + passCtx.resolution = inContext.Size; + passCtx.cameraID = GPUResources::Get().GetBindlessCameraID(inContext.CameraID); - if (light.Type != LightType::Directional || !light.CastShadows) + auto view = scene->m_Registry.view(); + for (auto e : view) { - continue; - } + auto [transform, light] = view.get(e); - light.LightMapIDs.clear(); - for (int i = 0; i < CSM_AMOUNT; i++) - { - light.LightMapIDs.push_back(light.m_ShadowMaps[i]->GetID()); - passCtx.cameraID = GPUResources::Get().GetBindlessCameraID(light.m_LightViews[i].CameraID); - passCtx.resolution = Vector2{ 4096, 4096 }; - shadowRenderPipeline->Render(passCtx, light.m_ShadowMaps[i]); + if (light.Type != LightType::Directional || !light.CastShadows) + { + continue; + } + + light.LightMapIDs.clear(); + for (int i = 0; i < CSM_AMOUNT; i++) + { + light.LightMapIDs.push_back(light.m_ShadowMaps[i]->GetID()); + passCtx.cameraID = GPUResources::Get().GetBindlessCameraID(light.m_LightViews[i].CameraID); + passCtx.resolution = Vector2{ 4096, 4096 }; + shadowRenderPipeline->Render(passCtx, light.m_ShadowMaps[i]); + } } } } + + } void VkSceneRenderer::DrawSceneView(RenderContext inContext) { PassRenderContext passCtx = { }; passCtx.cameraID = GPUResources::Get().GetBindlessCameraID(inContext.CameraID); - passCtx.resolution = Context.Size; + passCtx.resolution = inContext.Size; passCtx.commandBuffer = inContext.CommandBuffer; passCtx.scene = inContext.CurrentScene; + sceneRenderPipeline->Render(passCtx); + + inContext.CommandBuffer.TransitionImageLayout(sceneRenderPipeline->GetOutput(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + inContext.CommandBuffer.TransitionImageLayout(inContext.ViewportImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + inContext.CommandBuffer.CopyImageToImage(sceneRenderPipeline->GetOutput(), inContext.ViewportImage); + inContext.CommandBuffer.TransitionImageLayout(inContext.ViewportImage, VK_IMAGE_LAYOUT_GENERAL); + inContext.CommandBuffer.TransitionImageLayout(sceneRenderPipeline->GetOutput(), VK_IMAGE_LAYOUT_GENERAL); } // This will prepare all the data and upload it to the GPU before rendering the scene.