Compare commits
14 Commits
mono-PhysX
...
forward-re
| Author | SHA1 | Date | |
|---|---|---|---|
| f50824bdb1 | |||
| d11f8bb0c9 | |||
| 79707b77f5 | |||
| 971f16d526 | |||
| 5058d6a3a9 | |||
| f53d9134aa | |||
| 1b5fa1002d | |||
| d6d735900a | |||
| 230957f728 | |||
| 3c64abd77e | |||
| 1f4d7eff71 | |||
| b4d9dee045 | |||
| 4266a0b570 | |||
| ef4ea45edc |
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -35,3 +35,6 @@
|
||||
[submodule "Prism/vendor/efsw"]
|
||||
path = Prism/vendor/efsw
|
||||
url = https://github.com/SpartanJ/efsw
|
||||
[submodule "Prism/vendor/imgui-node-editor"]
|
||||
path = Prism/vendor/imgui-node-editor
|
||||
url = https://github.com/thedmd/imgui-node-editor.git
|
||||
|
||||
@ -23,4 +23,5 @@ endif ()
|
||||
|
||||
add_subdirectory(Prism)
|
||||
add_subdirectory(Sandbox)
|
||||
add_subdirectory(Editor)
|
||||
add_subdirectory(Editor)
|
||||
add_subdirectory(PrismRuntime)
|
||||
|
||||
@ -12,7 +12,7 @@ file(COPY ${IMGUI_INI} DESTINATION ${CMAKE_BINARY_DIR})
|
||||
file(GLOB DOTNET_LIBRARY library)
|
||||
file(COPY ${DOTNET_LIBRARY} DESTINATION ${CMAKE_BINARY_DIR})
|
||||
|
||||
file(GLOB_RECURSE SRC_SOURCE ./**.cpp)
|
||||
file(GLOB_RECURSE SRC_SOURCE ./Editor/**.cpp)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SRC_SOURCE})
|
||||
|
||||
|
||||
@ -15,10 +15,14 @@
|
||||
#include "Prism/Core/Input.h"
|
||||
#include "Prism/Core/Math/Math.h"
|
||||
#include "Prism/Editor/AssetEditorPanel.h"
|
||||
#include "Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.h"
|
||||
#include "Prism/Editor/PhysicsSettingsWindow.h"
|
||||
#include "Prism/Asset/AssetsManager.h"
|
||||
#include "Prism/Physics/Physics3D.h"
|
||||
#include "Prism/Renderer/Renderer2D.h"
|
||||
#include "Prism/Renderer/Renderer3D.h"
|
||||
#include "Prism/Script/ScriptEngine.h"
|
||||
#include "Prism/Script/ScriptWrappers.h"
|
||||
|
||||
namespace Prism
|
||||
{
|
||||
@ -51,8 +55,18 @@ namespace Prism
|
||||
NewScene();
|
||||
m_CurrentScene = m_EditorScene;
|
||||
|
||||
SceneRenderer::GetOptions().ShowGrid = true;
|
||||
|
||||
AssetEditorPanel::RegisterDefaultEditors();
|
||||
PBRMaterialEditor::InitPreviewRenderer();
|
||||
FileSystem::StartWatching();
|
||||
|
||||
m_ConsolePanel = CreateScope<ConsolePanel>();
|
||||
Script::SetLogCallback([this](const std::string& message)
|
||||
{
|
||||
if (m_ConsolePanel)
|
||||
m_ConsolePanel->AddMessage(message, ImVec4(1,1,1,1));
|
||||
});
|
||||
}
|
||||
|
||||
void EditorLayer::OnDetach()
|
||||
@ -63,6 +77,8 @@ namespace Prism
|
||||
|
||||
void EditorLayer::OnUpdate(const TimeStep deltaTime)
|
||||
{
|
||||
FileSystem::ProcessPendingEvents();
|
||||
|
||||
auto [x, y] = GetMouseViewportSpace();
|
||||
|
||||
SceneRenderer::SetFocusPoint({ x * 0.5f + 0.5f, y * 0.5f + 0.5f });
|
||||
@ -105,7 +121,7 @@ namespace Prism
|
||||
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
|
||||
const auto viewProj = m_EditorCamera.GetViewProjection();
|
||||
Renderer2D::BeginScene(viewProj, false);
|
||||
Renderer2D::DrawRotatedRect({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y }, {transform.Scale.x * collider.Size.x, transform.Scale.y * collider.Size.y}, transform.Rotation.z, { 0.0f, 0.0f, 1.0f, 1.0f });
|
||||
Renderer2D::DrawRotatedRect({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y , transform.Translation.z}, {transform.Scale.x * collider.Size.x, transform.Scale.y * collider.Size.y}, transform.Rotation.z, { 0.0f, 0.0f, 1.0f, 1.0f });
|
||||
Renderer2D::EndScene();
|
||||
Renderer::EndRenderPass();
|
||||
}
|
||||
@ -117,7 +133,7 @@ namespace Prism
|
||||
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
|
||||
const auto viewProj = m_EditorCamera.GetViewProjection();
|
||||
Renderer2D::BeginScene(viewProj, false);
|
||||
Renderer2D::DrawCircle({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y}, collider.Radius, { 0.0f, 1.0f, 1.0f, 1.0f });
|
||||
Renderer2D::DrawCircle({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y, transform.Translation.z}, collider.Radius, { 0.0f, 1.0f, 1.0f, 1.0f });
|
||||
Renderer2D::EndScene();
|
||||
Renderer::EndRenderPass();
|
||||
}
|
||||
@ -144,6 +160,37 @@ namespace Prism
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (m_SceneState == SceneState::Play)
|
||||
{
|
||||
if (Input::GetCursorMode() != CursorMode::Normal)
|
||||
{
|
||||
if (Input::IsKeyPressed(KeyCode::LEFT_CONTROL) && Input::IsKeyPressed(KeyCode::LEFT_ALT) && Input::IsKeyPressed(KeyCode::GRAVE_ACCENT))
|
||||
{
|
||||
Input::SetCursorMode(CursorMode::Normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto editingAsset = PBRMaterialEditor::GetEditingAsset();
|
||||
if (editingAsset && (editingAsset->PreviewIsDirty || !editingAsset->PreviewTexture))
|
||||
{
|
||||
PBRMaterialEditor::RenderMaterialPreview(editingAsset);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool renderedPreviewThisFrame = false;
|
||||
AssetsManager::ForEachAsset<PBRMaterialAsset>([&](Ref<PBRMaterialAsset> mat)
|
||||
{
|
||||
if (renderedPreviewThisFrame) return;
|
||||
if (mat->PreviewIsDirty || !mat->PreviewTexture)
|
||||
{
|
||||
PBRMaterialEditor::RenderMaterialPreview(mat);
|
||||
renderedPreviewThisFrame = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void EditorLayer::OnImGuiRender()
|
||||
@ -237,7 +284,7 @@ namespace Prism
|
||||
{
|
||||
// temp
|
||||
if (ImGui::MenuItem("Reload C# Assembly"))
|
||||
ScriptEngine::ReloadAssembly("assets/scripts/ExampleApp.dll");
|
||||
ScriptEngine::ReloadAssembly("assets/scripts/Assembly-Script.dll");
|
||||
|
||||
ImGui::MenuItem("Reload assembly on play", nullptr, &m_ReloadScriptOnPlay);
|
||||
ImGui::EndMenu();
|
||||
@ -246,7 +293,6 @@ namespace Prism
|
||||
if (ImGui::BeginMenu("Edit"))
|
||||
{
|
||||
ImGui::MenuItem("Physics Settings", nullptr, &m_ShowPhysicsSettings);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@ -262,6 +308,9 @@ namespace Prism
|
||||
Physics3D::DisconnectPVD();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem("GamePad View", nullptr, &m_ShowGamePadSettings);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@ -275,8 +324,9 @@ namespace Prism
|
||||
Entity selectedEntity = m_SelectionContext.front().Entity;
|
||||
if (selectedEntity.HasComponent<MeshComponent>())
|
||||
{
|
||||
Ref<Mesh> mesh = selectedEntity.GetComponent<MeshComponent>().Mesh;
|
||||
if (mesh)
|
||||
auto& meshComponent = selectedEntity.GetComponent<MeshComponent>();
|
||||
|
||||
if (Ref<Mesh> mesh = meshComponent.Mesh)
|
||||
{
|
||||
auto& materials = mesh->GetMaterials();
|
||||
static uint32_t selectedMaterialIndex = 0;
|
||||
@ -304,27 +354,13 @@ namespace Prism
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
/*
|
||||
for (uint32_t i = 0; i < materials.size(); i++)
|
||||
{
|
||||
const auto& materialInstance = materials[i];
|
||||
|
||||
ImGuiTreeNodeFlags node_flags = (selectedMaterialIndex == i ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_Leaf;
|
||||
bool opened = ImGui::TreeNodeEx((void*)(&materialInstance), node_flags, "%s", materialInstance->GetName().c_str());
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
selectedMaterialIndex = i;
|
||||
}
|
||||
if (opened)
|
||||
ImGui::TreePop();
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (selectedMaterialIndex < materials.size())
|
||||
{
|
||||
bool shouldUpdate = false;
|
||||
|
||||
auto& materialInstance = materials[selectedMaterialIndex];
|
||||
ImGui::Text("Shader: %s", materialInstance->GetShader()->GetName().c_str());
|
||||
// Textures ------------------------------------------------------------------------------
|
||||
@ -334,11 +370,26 @@ namespace Prism
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||
|
||||
auto& albedoColor = materialInstance->Get<glm::vec3>("u_AlbedoColor");
|
||||
auto& albedoColor = materialInstance->Get<glm::vec4>("u_AlbedoColor");
|
||||
bool useAlbedoMap = materialInstance->Get<float>("u_AlbedoTexToggle");
|
||||
Ref<Texture2D> albedoMap = materialInstance->TryGetResource<Texture2D>("u_AlbedoTexture");
|
||||
|
||||
ImGui::Image(albedoMap ? (ImTextureRef)albedoMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const auto data = ImGui::AcceptDragDropPayload("asset_payload"))
|
||||
{
|
||||
AssetHandle assetHandle = *(AssetHandle*)data->Data;
|
||||
if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture))
|
||||
{
|
||||
albedoMap = AssetsManager::GetAsset<Texture2D>(assetHandle);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
@ -351,28 +402,23 @@ namespace Prism
|
||||
ImGui::Image((ImTextureRef)albedoMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty())
|
||||
{
|
||||
albedoMap = Texture2D::Create(filename, true/*m_AlbedoInput.SRGB*/);
|
||||
materialInstance->Set("u_AlbedoTexture", albedoMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginGroup();
|
||||
if (ImGui::Checkbox("Use##AlbedoMap", &useAlbedoMap))
|
||||
materialInstance->Set<float>("u_AlbedoTexToggle", useAlbedoMap ? 1.0f : 0.0f);
|
||||
|
||||
/*if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB))
|
||||
{
|
||||
if (m_AlbedoInput.TextureMap)
|
||||
m_AlbedoInput.TextureMap = Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB);
|
||||
}*/
|
||||
materialInstance->Set<float>("u_AlbedoTexToggle", useAlbedoMap ? 1.0f : 0.0f);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(albedoColor), ImGuiColorEditFlags_NoInputs);
|
||||
if (ImGui::ColorEdit4("Color##Albedo", glm::value_ptr(albedoColor), ImGuiColorEditFlags_NoInputs))
|
||||
{
|
||||
meshComponent.UpdateMaterials(selectedMaterialIndex);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -385,6 +431,21 @@ namespace Prism
|
||||
Ref<Texture2D> normalMap = materialInstance->TryGetResource<Texture2D>("u_NormalTexture");
|
||||
|
||||
ImGui::Image(normalMap ? (ImTextureRef)normalMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const auto data = ImGui::AcceptDragDropPayload("asset_payload"))
|
||||
{
|
||||
AssetHandle assetHandle = *(AssetHandle*)data->Data;
|
||||
if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture))
|
||||
{
|
||||
normalMap = AssetsManager::GetAsset<Texture2D>(assetHandle);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
@ -403,12 +464,16 @@ namespace Prism
|
||||
{
|
||||
normalMap = Texture2D::Create(filename);
|
||||
materialInstance->Set("u_NormalTexture", normalMap);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("Use##NormalMap", &useNormalMap))
|
||||
{
|
||||
materialInstance->Set<float>("u_NormalTexToggle", useNormalMap ? 1.0f : 0.0f);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -422,6 +487,21 @@ namespace Prism
|
||||
Ref<Texture2D> metalnessMap = materialInstance->TryGetResource<Texture2D>("u_MetalnessTexture");
|
||||
|
||||
ImGui::Image(metalnessMap ? (ImTextureRef)metalnessMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const auto data = ImGui::AcceptDragDropPayload("asset_payload"))
|
||||
{
|
||||
AssetHandle assetHandle = *(AssetHandle*)data->Data;
|
||||
if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture))
|
||||
{
|
||||
metalnessMap = AssetsManager::GetAsset<Texture2D>(assetHandle);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
@ -434,20 +514,18 @@ namespace Prism
|
||||
ImGui::Image((ImTextureRef)metalnessMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty())
|
||||
{
|
||||
metalnessMap = Texture2D::Create(filename);
|
||||
materialInstance->Set("u_MetalnessTexture", metalnessMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("Use##MetalnessMap", &useMetalnessMap))
|
||||
{
|
||||
materialInstance->Set<float>("u_MetalnessTexToggle", useMetalnessMap ? 1.0f : 0.0f);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat("Value##MetalnessInput", &metalnessValue, 0.0f, 1.0f);
|
||||
if (ImGui::SliderFloat("Value##MetalnessInput", &metalnessValue, 0.0f, 1.0f))
|
||||
{
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -460,6 +538,20 @@ namespace Prism
|
||||
Ref<Texture2D> roughnessMap = materialInstance->TryGetResource<Texture2D>("u_RoughnessTexture");
|
||||
|
||||
ImGui::Image(roughnessMap ? (ImTextureRef)roughnessMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const auto data = ImGui::AcceptDragDropPayload("asset_payload"))
|
||||
{
|
||||
AssetHandle assetHandle = *(AssetHandle*)data->Data;
|
||||
if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture))
|
||||
{
|
||||
roughnessMap = AssetsManager::GetAsset<Texture2D>(assetHandle);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
@ -472,22 +564,21 @@ namespace Prism
|
||||
ImGui::Image((ImTextureRef)roughnessMap->GetRendererID(), ImVec2(384, 384));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsItemClicked())
|
||||
{
|
||||
if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty())
|
||||
{
|
||||
roughnessMap = Texture2D::Create(filename);
|
||||
materialInstance->Set("u_RoughnessTexture", roughnessMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("Use##RoughnessMap", &useRoughnessMap))
|
||||
{
|
||||
materialInstance->Set<float>("u_RoughnessTexToggle", useRoughnessMap ? 1.0f : 0.0f);
|
||||
shouldUpdate = true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SliderFloat("Value##RoughnessInput", &roughnessValue, 0.0f, 1.0f);
|
||||
if (ImGui::SliderFloat("Value##RoughnessInput", &roughnessValue, 0.0f, 1.0f))
|
||||
{
|
||||
shouldUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldUpdate) meshComponent.UpdateMaterials(selectedMaterialIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -505,7 +596,11 @@ namespace Prism
|
||||
m_ObjectsPanel->OnImGuiRender();
|
||||
|
||||
m_SceneHierarchyPanel->OnImGuiRender();
|
||||
m_EditorCamera.OnImGuiRender();
|
||||
// m_EditorCamera.OnImGuiRender();
|
||||
m_ConsolePanel->OnImGuiRender();
|
||||
|
||||
// GamePad
|
||||
DrawGamepadDebugPanel(m_ShowGamePadSettings);
|
||||
|
||||
// Editor Panel ------------------------------------------------------------------------------
|
||||
ImGui::Begin("Environment");
|
||||
@ -517,6 +612,20 @@ namespace Prism
|
||||
|
||||
UI::PropertySlider("Exposure", m_EditorCamera.GetExposure(), 0.0f, 5.0f);
|
||||
|
||||
ImGui::Separator();
|
||||
float near = m_EditorCamera.GetNear();
|
||||
float far = m_EditorCamera.GetFar();
|
||||
|
||||
if (UI::Property("Near", near))
|
||||
{
|
||||
m_EditorCamera.SetNearFar(near, far);
|
||||
}
|
||||
if (UI::Property("Far", far))
|
||||
{
|
||||
m_EditorCamera.SetNearFar(near, far);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
float physics2DGravity = m_EditorScene->GetPhysics2DGravity();
|
||||
if (UI::Property("2D World Gravity", physics2DGravity, -100.0f, 100.0f))
|
||||
@ -599,7 +708,6 @@ namespace Prism
|
||||
{
|
||||
SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
m_EditorScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
m_EditorCamera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
||||
m_EditorCamera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||
|
||||
@ -654,7 +762,7 @@ namespace Prism
|
||||
m_ViewportBounds[1] = { maxBound.x, maxBound.y };
|
||||
|
||||
// ImGuizmo
|
||||
if (m_GizmoType != -1 && !m_SelectionContext.empty() && m_SceneState == SceneState::Edit)
|
||||
if ((m_ViewportPanelFocused || m_ViewportPanelHovered) && m_GizmoType != -1 && !m_SelectionContext.empty() && m_SceneState == SceneState::Edit)
|
||||
{
|
||||
auto& selection = m_SelectionContext[0];
|
||||
|
||||
@ -856,15 +964,19 @@ namespace Prism
|
||||
|
||||
if (ImViewGuizmo::Rotate(cameraPos, cameraRot, glm::vec3(0.0f), gizmoCenter))
|
||||
{
|
||||
if (m_ViewportPanelFocused || m_ViewportPanelHovered)
|
||||
{
|
||||
glm::vec3 forward = cameraRot * glm::vec3(0.0f, 0.0f, -1.0f);
|
||||
float newPitch = glm::asin(glm::clamp(-forward.y, -1.0f, 1.0f));
|
||||
float newYaw = -glm::atan(forward.x, -forward.z);
|
||||
|
||||
glm::vec3 forward = cameraRot * glm::vec3(0.0f, 0.0f, -1.0f);
|
||||
float newPitch = glm::asin(glm::clamp(-forward.y, -1.0f, 1.0f));
|
||||
float newYaw = -glm::atan(forward.x, -forward.z);
|
||||
float distance = glm::length(cameraPos - focusPosition);
|
||||
m_EditorCamera.SetDistance(distance);
|
||||
m_EditorCamera.SetFocusPosition(focusPosition);
|
||||
m_EditorCamera.SetYawPitch(newYaw, newPitch);
|
||||
|
||||
}
|
||||
|
||||
float distance = glm::length(cameraPos - focusPosition);
|
||||
m_EditorCamera.SetDistance(distance);
|
||||
m_EditorCamera.SetFocusPosition(focusPosition);
|
||||
m_EditorCamera.SetYawPitch(newYaw, newPitch);
|
||||
}
|
||||
}
|
||||
|
||||
@ -929,20 +1041,20 @@ namespace Prism
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (e.GetKeyCode())
|
||||
{
|
||||
case KeyCode::DELETE:
|
||||
if (m_SelectionContext.size())
|
||||
switch (e.GetKeyCode())
|
||||
{
|
||||
const Entity selectedEntity = m_SelectionContext[0].Entity;
|
||||
m_EditorScene->DestroyEntity(selectedEntity);
|
||||
m_SelectionContext.clear();
|
||||
m_EditorScene->SetSelectedEntity({});
|
||||
m_SceneHierarchyPanel->SetSelected({});
|
||||
case KeyCode::DELETE:
|
||||
if (m_SelectionContext.size())
|
||||
{
|
||||
const Entity selectedEntity = m_SelectionContext[0].Entity;
|
||||
m_EditorScene->DestroyEntity(selectedEntity);
|
||||
m_SelectionContext.clear();
|
||||
m_EditorScene->SetSelectedEntity({});
|
||||
m_SceneHierarchyPanel->SetSelected({});
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (Input::IsKeyPressed(KeyCode::LEFT_CONTROL))
|
||||
@ -1020,7 +1132,6 @@ namespace Prism
|
||||
continue;
|
||||
|
||||
auto& submeshes = mesh->GetSubmeshes();
|
||||
float lastT = std::numeric_limits<float>::max();
|
||||
for (uint32_t i = 0; i < submeshes.size(); i++)
|
||||
{
|
||||
auto& submesh = submeshes[i];
|
||||
@ -1054,17 +1165,6 @@ namespace Prism
|
||||
});
|
||||
if (!m_SelectionContext.empty())
|
||||
{
|
||||
if (auto alreadySelectedEntity = m_SceneHierarchyPanel->GetSelected();
|
||||
m_SelectionContext.size() != 1 && alreadySelectedEntity)
|
||||
{
|
||||
const auto alreadySelectedEntityID = alreadySelectedEntity.GetUUID();
|
||||
|
||||
for (const auto& selectedEntity : m_SelectionContext)
|
||||
{
|
||||
if (alreadySelectedEntityID == selectedEntity.Entity.GetUUID()) continue;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
OnSelected(m_SelectionContext[0]);
|
||||
}
|
||||
}
|
||||
@ -1105,6 +1205,249 @@ namespace Prism
|
||||
Application::Get().GetWindow().SetTitle(title);
|
||||
}
|
||||
|
||||
void EditorLayer::DrawGamepadDebugPanel(bool& p_open)
|
||||
{
|
||||
if (!p_open)
|
||||
return;
|
||||
|
||||
ImGui::Begin("Gamepad Debug", &p_open);
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
|
||||
bool anyConnected = false;
|
||||
for (int jid = 0; jid <= 15; ++jid)
|
||||
{
|
||||
if (!Input::IsGamepadConnected(jid))
|
||||
continue;
|
||||
|
||||
anyConnected = true;
|
||||
const char* name = Input::GetGamepadName(jid);
|
||||
bool isGamepad = Input::IsGamepad(jid);
|
||||
|
||||
// 使用 CollapsingHeader 或 TreeNodeEx 均可,这里用 TreeNodeEx 保持与之前类似
|
||||
if (ImGui::TreeNodeEx((void*)(intptr_t)jid, ImGuiTreeNodeFlags_DefaultOpen,
|
||||
"Joystick %d: %s%s", jid, name, isGamepad ? " (mapped)" : ""))
|
||||
{
|
||||
// ---------- 1. 摇杆与主要按钮行 ----------
|
||||
const float stickRadius = 40.0f; // 圆形摇杆半径
|
||||
const ImVec2 stickSize(stickRadius * 2, stickRadius * 2);
|
||||
const float buttonSize = 30.0f; // 普通按钮(ABXY)的大小
|
||||
const float dpadButtonSize = 30.0f; // 十字键按钮稍小
|
||||
|
||||
// 左摇杆区域
|
||||
auto drawStick = [&](const char* label, float x, float y)
|
||||
{
|
||||
// 注意:GLFW 左 Y 向上为负,右 Y 向上为负,统一取反
|
||||
y = -y;
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Text("%s", label);
|
||||
const ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
const ImVec2 center(pos.x + stickRadius, pos.y + stickRadius);
|
||||
|
||||
// 圆形底板
|
||||
drawList->AddCircleFilled(center, stickRadius, IM_COL32(30,30,30,255));
|
||||
drawList->AddCircle(center, stickRadius, IM_COL32(100,100,100,255), 0, 2.0f);
|
||||
// 十字参考线
|
||||
drawList->AddLine(ImVec2(center.x - stickRadius, center.y), ImVec2(center.x + stickRadius, center.y), IM_COL32(70,70,70,255));
|
||||
drawList->AddLine(ImVec2(center.x, center.y - stickRadius), ImVec2(center.x, center.y + stickRadius), IM_COL32(70,70,70,255));
|
||||
|
||||
// 摇杆位置点
|
||||
const float len = sqrtf(x*x + y*y);
|
||||
float clampX = x, clampY = y;
|
||||
if (len > 1.0f) { clampX /= len; clampY /= len; }
|
||||
const float dotX = center.x + clampX * stickRadius;
|
||||
const float dotY = center.y - clampY * stickRadius; // 屏幕Y向下,故用减
|
||||
drawList->AddCircleFilled(ImVec2(dotX, dotY), 6.0f, IM_COL32(255,80,80,255));
|
||||
if (len > 0.99f)
|
||||
drawList->AddCircle(center, stickRadius, IM_COL32(255,255,0,150), 0, 3.0f);
|
||||
|
||||
ImGui::Dummy(stickSize);
|
||||
ImGui::EndGroup();
|
||||
};
|
||||
|
||||
// 十字键(上下左右)
|
||||
auto drawDPad = [&]()
|
||||
{
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Text("DPad");
|
||||
ImVec2 base = ImGui::GetCursorScreenPos();
|
||||
// 上
|
||||
bool up = Prism::Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::DPAD_UP);
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x + dpadButtonSize, base.y));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, up ? ImVec4(0.0f,1.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("U", ImVec2(dpadButtonSize, dpadButtonSize));
|
||||
ImGui::PopStyleColor();
|
||||
// 左
|
||||
bool left = Prism::Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::DPAD_LEFT);
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x, base.y + dpadButtonSize));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, left ? ImVec4(0.0f,1.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("L", ImVec2(dpadButtonSize, dpadButtonSize));
|
||||
ImGui::PopStyleColor();
|
||||
// 右
|
||||
bool right = Prism::Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::DPAD_RIGHT);
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x + 2*dpadButtonSize, base.y + dpadButtonSize));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, right ? ImVec4(0.0f,1.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("R", ImVec2(dpadButtonSize, dpadButtonSize));
|
||||
ImGui::PopStyleColor();
|
||||
// 下
|
||||
bool down = Prism::Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::DPAD_DOWN);
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x + dpadButtonSize, base.y + 2*dpadButtonSize));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, down ? ImVec4(0.0f,1.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("D", ImVec2(dpadButtonSize, dpadButtonSize));
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// 让 Group 大小包含整个十字区域
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x, base.y + 3*dpadButtonSize));
|
||||
ImGui::Dummy(ImVec2(3*dpadButtonSize, 0));
|
||||
ImGui::EndGroup();
|
||||
};
|
||||
|
||||
// ABXY 按钮组(按手柄实际位置排列:X左 Y上 B右 A下)
|
||||
auto drawABXY = [&]()
|
||||
{
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Text("Buttons");
|
||||
ImVec2 base = ImGui::GetCursorScreenPos();
|
||||
// Y 上
|
||||
bool y = Prism::Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::Y);
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x + buttonSize, base.y));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, y ? ImVec4(1.0f,0.8f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("Y", ImVec2(buttonSize, buttonSize));
|
||||
ImGui::PopStyleColor();
|
||||
// X 左
|
||||
bool x = Prism::Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::X);
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x, base.y + buttonSize));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, x ? ImVec4(0.0f,0.7f,1.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("X", ImVec2(buttonSize, buttonSize));
|
||||
ImGui::PopStyleColor();
|
||||
// B 右
|
||||
bool b = Prism::Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::B);
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x + 2*buttonSize, base.y + buttonSize));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, b ? ImVec4(1.0f,0.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("B", ImVec2(buttonSize, buttonSize));
|
||||
ImGui::PopStyleColor();
|
||||
// A 下
|
||||
bool a = Prism::Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::A);
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x + buttonSize, base.y + 2*buttonSize));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, a ? ImVec4(0.0f,1.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("A", ImVec2(buttonSize, buttonSize));
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(base.x, base.y + 3*buttonSize));
|
||||
ImGui::Dummy(ImVec2(3*buttonSize, 0));
|
||||
ImGui::EndGroup();
|
||||
};
|
||||
|
||||
// 右摇杆区域
|
||||
auto drawRightStick = [&](float x, float y)
|
||||
{
|
||||
y = -y;
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Text("R Stick");
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 center(pos.x + stickRadius, pos.y + stickRadius);
|
||||
drawList->AddCircleFilled(center, stickRadius, IM_COL32(30,30,30,255));
|
||||
drawList->AddCircle(center, stickRadius, IM_COL32(100,100,100,255), 0, 2.0f);
|
||||
drawList->AddLine(ImVec2(center.x - stickRadius, center.y), ImVec2(center.x + stickRadius, center.y), IM_COL32(70,70,70,255));
|
||||
drawList->AddLine(ImVec2(center.x, center.y - stickRadius), ImVec2(center.x, center.y + stickRadius), IM_COL32(70,70,70,255));
|
||||
|
||||
float len = sqrtf(x*x + y*y);
|
||||
float clampX = x, clampY = y;
|
||||
if (len > 1.0f) { clampX /= len; clampY /= len; }
|
||||
float dotX = center.x + clampX * stickRadius;
|
||||
float dotY = center.y - clampY * stickRadius;
|
||||
drawList->AddCircleFilled(ImVec2(dotX, dotY), 6.0f, IM_COL32(255,80,80,255));
|
||||
if (len > 0.99f)
|
||||
drawList->AddCircle(center, stickRadius, IM_COL32(255,255,0,150), 0, 3.0f);
|
||||
|
||||
ImGui::Dummy(stickSize);
|
||||
ImGui::EndGroup();
|
||||
};
|
||||
|
||||
// 获取摇杆当前值
|
||||
const float lx = Input::GetGamepadAxis(jid, GamepadAxis::LEFT_X);
|
||||
const float ly = Input::GetGamepadAxis(jid, GamepadAxis::LEFT_Y);
|
||||
const float rx = Input::GetGamepadAxis(jid, GamepadAxis::RIGHT_X);
|
||||
const float ry = Input::GetGamepadAxis(jid, GamepadAxis::RIGHT_Y);
|
||||
|
||||
// ----- 第一行:左摇杆 | 十字键 | ABXY | 右摇杆 -----
|
||||
ImGui::BeginGroup();
|
||||
// 缩进稍微调整
|
||||
ImGui::Columns(4, "MainControls", false);
|
||||
ImGui::SetColumnWidth(0, stickSize.x + 10);
|
||||
ImGui::SetColumnWidth(1, 3*dpadButtonSize + 10);
|
||||
ImGui::SetColumnWidth(2, 3*buttonSize + 10);
|
||||
ImGui::SetColumnWidth(3, stickSize.x + 10);
|
||||
|
||||
drawStick("L Stick", lx, ly);
|
||||
ImGui::NextColumn();
|
||||
drawDPad();
|
||||
ImGui::NextColumn();
|
||||
drawABXY();
|
||||
ImGui::NextColumn();
|
||||
drawRightStick(rx, ry);
|
||||
ImGui::Columns(1);
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// ----- 第二行:肩键 LB/RB 和扳机轴 -----
|
||||
ImGui::Text("Bumpers & Triggers");
|
||||
bool lb = Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::LEFT_BUMPER);
|
||||
bool rb = Input::IsGamepadButtonPressed(jid, Prism::GamepadButton::RIGHT_BUMPER);
|
||||
float lt = Input::GetGamepadAxis(jid, Prism::GamepadAxis::LEFT_TRIGGER);
|
||||
float rt = Input::GetGamepadAxis(jid, Prism::GamepadAxis::RIGHT_TRIGGER);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, lb ? ImVec4(0.0f,1.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("LB", ImVec2(40, 20));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
ImGui::ProgressBar(lt, ImVec2(100, 20), "");
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("LT %.2f", lt);
|
||||
|
||||
ImGui::SameLine(0, 30);
|
||||
|
||||
ImGui::ProgressBar(rt, ImVec2(100, 20), "");
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("RT %.2f", rt);
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, rb ? ImVec4(0.0f,1.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button("RB", ImVec2(40, 20));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// ----- 第三行:功能键 Back, Guide, Start, LThumb, RThumb -----
|
||||
ImGui::Text("Function Keys");
|
||||
auto drawFuncBtn = [&](const char* label, Prism::GamepadButton btn)
|
||||
{
|
||||
bool pressed = Input::IsGamepadButtonPressed(jid, btn);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, pressed ? ImVec4(0.0f,1.0f,0.0f,1.0f) : ImVec4(0.3f,0.3f,0.3f,1.0f));
|
||||
ImGui::Button(label, ImVec2(60, 25));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(0, 4);
|
||||
};
|
||||
|
||||
drawFuncBtn("Back", GamepadButton::BACK);
|
||||
drawFuncBtn("Guide", GamepadButton::GUIDE);
|
||||
drawFuncBtn("Start", GamepadButton::START);
|
||||
ImGui::SameLine(0, 20);
|
||||
drawFuncBtn("LThumb", GamepadButton::LEFT_THUMB);
|
||||
drawFuncBtn("RThumb", GamepadButton::RIGHT_THUMB);
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyConnected)
|
||||
ImGui::Text("No gamepads connected.");
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
std::pair<float, float> EditorLayer::GetMouseViewportSpace() const
|
||||
{
|
||||
auto [mx, my] = ImGui::GetMousePos(); // Input::GetMousePosition();
|
||||
@ -1164,8 +1507,16 @@ namespace Prism
|
||||
UpdateWindowTitle("Untitled Scene");
|
||||
m_SceneFilePath = std::string();
|
||||
|
||||
m_EditorCamera = EditorCamera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 100.0f));
|
||||
m_EditorCamera = EditorCamera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 1000.0f));
|
||||
m_SelectionContext.clear();
|
||||
|
||||
// new Scene with a default sky light
|
||||
auto newEntity = m_EditorScene->CreateEntity("Sky Light");
|
||||
auto& slc = newEntity.AddComponent<SkyLightComponent>();
|
||||
slc.DynamicSky = true;
|
||||
|
||||
Ref<TextureCube> preethamEnv = Renderer3D::CreatePreethamSky(slc.TurbidityAzimuthInclination);
|
||||
slc.SceneEnvironment = Ref<Environment>::Create(preethamEnv, preethamEnv);
|
||||
}
|
||||
|
||||
void EditorLayer::OpenScene()
|
||||
@ -1232,7 +1583,7 @@ namespace Prism
|
||||
m_SceneState = SceneState::Play;
|
||||
|
||||
if (m_ReloadScriptOnPlay)
|
||||
ScriptEngine::ReloadAssembly("assets/scripts/ExampleApp.dll");
|
||||
ScriptEngine::ReloadAssembly("assets/Scripts/Assembly-CSharp.dll");
|
||||
|
||||
m_RuntimeScene = Ref<Scene>::Create();
|
||||
m_EditorScene->CopyTo(m_RuntimeScene);
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#ifndef EDITORLAYER_H
|
||||
#define EDITORLAYER_H
|
||||
|
||||
#include "Panels/ConsolePanel.h"
|
||||
#include "Prism.h"
|
||||
#include "Prism/Editor/ContentBrowserPanel.h"
|
||||
#include "Prism/Editor/ObjectsPanel.h"
|
||||
@ -32,6 +33,10 @@ namespace Prism
|
||||
void SelectEntity(Entity entity);
|
||||
|
||||
void UpdateWindowTitle(const std::string& sceneName);
|
||||
|
||||
// GamePad Utils
|
||||
void DrawGamepadDebugPanel(bool& p_open);
|
||||
|
||||
private:
|
||||
std::pair<float, float> GetMouseViewportSpace() const;
|
||||
std::pair<glm::vec3, glm::vec3> CastRay(float mx, float my);
|
||||
@ -144,12 +149,16 @@ namespace Prism
|
||||
bool m_ViewportPanelHovered = false;
|
||||
bool m_ViewportPanelFocused = false;
|
||||
bool m_ShowPhysicsSettings = false;
|
||||
bool m_ShowGamePadSettings = false;
|
||||
|
||||
enum class SceneState
|
||||
{
|
||||
Edit = 0, Play = 1, Pause = 2
|
||||
};
|
||||
SceneState m_SceneState = SceneState::Edit;
|
||||
|
||||
private:
|
||||
Scope<ConsolePanel> m_ConsolePanel;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
66
Editor/Editor/Panels/ConsolePanel.cpp
Normal file
66
Editor/Editor/Panels/ConsolePanel.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// Created by Atdunbg on 2026/3/26.
|
||||
//
|
||||
|
||||
#include "ConsolePanel.h"
|
||||
|
||||
namespace Prism
|
||||
{
|
||||
ConsolePanel::ConsolePanel()
|
||||
{
|
||||
// 预留一些空间
|
||||
m_Messages.reserve(1000);
|
||||
}
|
||||
|
||||
void ConsolePanel::OnImGuiRender()
|
||||
{
|
||||
ImGui::Begin("Console");
|
||||
|
||||
// 工具栏
|
||||
if (ImGui::Button("Clear"))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||
m_Messages.clear();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Auto-scroll", &m_AutoScroll);
|
||||
ImGui::SameLine();
|
||||
m_Filter.Draw("Filter", 200);
|
||||
|
||||
// 消息列表区域
|
||||
ImGui::BeginChild("ScrollingRegion", ImVec2(0, 0), ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||
for (const auto& [msg, color] : m_Messages)
|
||||
{
|
||||
if (m_Filter.PassFilter(msg.c_str()))
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
ImGui::TextUnformatted(msg.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ScrollToBottom)
|
||||
{
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
m_ScrollToBottom = false;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ConsolePanel::AddMessage(const std::string& message, ImVec4 color)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||
m_Messages.emplace_back(message, color);
|
||||
while (m_Messages.size() > 5000)
|
||||
m_Messages.erase(m_Messages.begin());
|
||||
|
||||
if (m_AutoScroll && !m_ScrollToBottom)
|
||||
m_ScrollToBottom = true;
|
||||
}
|
||||
}
|
||||
31
Editor/Editor/Panels/ConsolePanel.h
Normal file
31
Editor/Editor/Panels/ConsolePanel.h
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Created by Atdunbg on 2026/3/26.
|
||||
//
|
||||
|
||||
#ifndef PRISM_CONSOLEPANEL_H
|
||||
#define PRISM_CONSOLEPANEL_H
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
namespace Prism
|
||||
{
|
||||
class ConsolePanel
|
||||
{
|
||||
public:
|
||||
ConsolePanel();
|
||||
void OnImGuiRender();
|
||||
|
||||
void AddMessage(const std::string& message, ImVec4 color = ImVec4(1,1,1,1));
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string, ImVec4>> m_Messages;
|
||||
ImGuiTextFilter m_Filter;
|
||||
bool m_AutoScroll = true;
|
||||
bool m_ScrollToBottom = false;
|
||||
std::mutex m_Mutex;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //PRISM_CONSOLEPANEL_H
|
||||
BIN
Editor/assets/editor/model.png
Normal file
BIN
Editor/assets/editor/model.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
BIN
Editor/assets/editor/texture.png
Normal file
BIN
Editor/assets/editor/texture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
Binary file not shown.
389
Editor/assets/scenes/FPS.scene
Normal file
389
Editor/assets/scenes/FPS.scene
Normal file
@ -0,0 +1,389 @@
|
||||
Scene: Scene Name
|
||||
Environment:
|
||||
AssetHandle: 10745193190519058183
|
||||
Entities:
|
||||
- Entity: 4944419254382500800
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Directional Light
|
||||
TransformComponent:
|
||||
Position: [0, 0, 0]
|
||||
Rotation: [-2.2312348, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
DirectionalLightComponent:
|
||||
Radiance: [1, 1, 1]
|
||||
CastShadows: true
|
||||
SoftShadows: true
|
||||
LightSize: 0.5
|
||||
- Entity: 5099152432245948441
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: venice_dawn_1_4k
|
||||
TransformComponent:
|
||||
Position: [0, 0, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
SkyLightComponent:
|
||||
EnvironmentMap: 10745193190519058183
|
||||
EnvironmentAssetPath: assets/env/venice_dawn_1_4k.hdr
|
||||
Intensity: 1
|
||||
Angle: 0
|
||||
DynamicSky: false
|
||||
TurbidityAzimuthInclination: [2, 0, 0]
|
||||
- Entity: 10732070446010033158
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [0, -2.6466873, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [100, 1, 100]
|
||||
MeshComponent:
|
||||
AssetID: 14957733959243172548
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
Materials:
|
||||
Slot 0:
|
||||
AssetHandle: 0
|
||||
AssetPath: ""
|
||||
RigidBodyComponent:
|
||||
BodyType: 0
|
||||
Mass: 1
|
||||
LinearDrag: 0
|
||||
AngularDrag: 0.05
|
||||
DisableGravity: false
|
||||
IsKinematic: false
|
||||
Layer: 0
|
||||
Constraints:
|
||||
LockPositionX: false
|
||||
LockPositionY: false
|
||||
LockPositionZ: false
|
||||
LockRotationX: false
|
||||
LockRotationY: false
|
||||
LockRotationZ: false
|
||||
BoxColliderComponent:
|
||||
Offset: [0, 0, 0]
|
||||
Size: [2, 2, 2]
|
||||
IsTrigger: false
|
||||
Material: 0
|
||||
MaterialPath: ""
|
||||
- Entity: 9267298328378270409
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Player
|
||||
TransformComponent:
|
||||
Position: [0, 0.70693016, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
ScriptComponent:
|
||||
ModuleName: FPSExample.FPSPlayer
|
||||
StoredFields:
|
||||
- Name: m_Radius
|
||||
Type: 1
|
||||
Data: 0
|
||||
- Name: WalkingSpeed
|
||||
Type: 1
|
||||
Data: 2
|
||||
- Name: RunSpeed
|
||||
Type: 1
|
||||
Data: 5
|
||||
- Name: JumpForce
|
||||
Type: 1
|
||||
Data: 1
|
||||
- Name: TorqueStrength
|
||||
Type: 1
|
||||
Data: 0
|
||||
- Name: MouseSensitivity
|
||||
Type: 1
|
||||
Data: 10
|
||||
- Name: CameraForwardOffset
|
||||
Type: 1
|
||||
Data: -2
|
||||
- Name: CameraYOffset
|
||||
Type: 1
|
||||
Data: 2
|
||||
MeshComponent:
|
||||
AssetID: 8763440120556133680
|
||||
AssetPath: assets/meshes/Default/Capsule.fbx
|
||||
Materials:
|
||||
Slot 0:
|
||||
AssetHandle: 0
|
||||
AssetPath: ""
|
||||
RigidBodyComponent:
|
||||
BodyType: 1
|
||||
Mass: 1
|
||||
LinearDrag: 0
|
||||
AngularDrag: 0.05
|
||||
DisableGravity: false
|
||||
IsKinematic: false
|
||||
Layer: 0
|
||||
Constraints:
|
||||
LockPositionX: false
|
||||
LockPositionY: false
|
||||
LockPositionZ: false
|
||||
LockRotationX: true
|
||||
LockRotationY: false
|
||||
LockRotationZ: true
|
||||
MeshColliderComponent:
|
||||
IsConvex: true
|
||||
IsTrigger: false
|
||||
OverrideMesh: false
|
||||
Material: 0
|
||||
MaterialPath: ""
|
||||
- Entity: 8114736924719261351
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Camera
|
||||
TransformComponent:
|
||||
Position: [0, 0.8097433, 4.573171]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
CameraComponent:
|
||||
Camera:
|
||||
ProjectionType: 0
|
||||
PerspectiveFOV: 45
|
||||
PerspectiveNear: 0.01
|
||||
PerspectiveFar: 10000
|
||||
OrthographicSize: 10
|
||||
OrthographicNear: -1
|
||||
OrthographicFar: 1
|
||||
Primary: true
|
||||
- Entity: 4208267561919679628
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [-2.6417403, 1.4724115, -4.8956265]
|
||||
Rotation: [-0.4034239, 0, 0]
|
||||
Scale: [1, 0.99999994, 0.99999994]
|
||||
MeshComponent:
|
||||
AssetID: 14957733959243172548
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
Materials:
|
||||
Slot 0:
|
||||
AssetHandle: 0
|
||||
AssetPath: ""
|
||||
RigidBodyComponent:
|
||||
BodyType: 1
|
||||
Mass: 1
|
||||
LinearDrag: 0
|
||||
AngularDrag: 0.05
|
||||
DisableGravity: true
|
||||
IsKinematic: false
|
||||
Layer: 0
|
||||
Constraints:
|
||||
LockPositionX: false
|
||||
LockPositionY: false
|
||||
LockPositionZ: false
|
||||
LockRotationX: false
|
||||
LockRotationY: false
|
||||
LockRotationZ: false
|
||||
BoxColliderComponent:
|
||||
Offset: [0, 0, 0]
|
||||
Size: [2, 2, 2]
|
||||
IsTrigger: false
|
||||
Material: 0
|
||||
MaterialPath: ""
|
||||
- Entity: 3328246672296261054
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [1.736814, 1.4724115, -0.88378817]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
MeshComponent:
|
||||
AssetID: 14957733959243172548
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
Materials:
|
||||
Slot 0:
|
||||
AssetHandle: 0
|
||||
AssetPath: ""
|
||||
RigidBodyComponent:
|
||||
BodyType: 1
|
||||
Mass: 1
|
||||
LinearDrag: 0
|
||||
AngularDrag: 0.05
|
||||
DisableGravity: false
|
||||
IsKinematic: false
|
||||
Layer: 0
|
||||
Constraints:
|
||||
LockPositionX: false
|
||||
LockPositionY: false
|
||||
LockPositionZ: false
|
||||
LockRotationX: false
|
||||
LockRotationY: false
|
||||
LockRotationZ: false
|
||||
BoxColliderComponent:
|
||||
Offset: [0, 0, 0]
|
||||
Size: [2, 2, 2]
|
||||
IsTrigger: false
|
||||
Material: 0
|
||||
MaterialPath: ""
|
||||
- Entity: 12935252585493481950
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [-1.5106764, 6.237644, -4.2181306]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
MeshComponent:
|
||||
AssetID: 14957733959243172548
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
Materials:
|
||||
Slot 0:
|
||||
AssetHandle: 0
|
||||
AssetPath: ""
|
||||
RigidBodyComponent:
|
||||
BodyType: 1
|
||||
Mass: 1
|
||||
LinearDrag: 0
|
||||
AngularDrag: 0.05
|
||||
DisableGravity: false
|
||||
IsKinematic: false
|
||||
Layer: 0
|
||||
Constraints:
|
||||
LockPositionX: false
|
||||
LockPositionY: false
|
||||
LockPositionZ: false
|
||||
LockRotationX: false
|
||||
LockRotationY: false
|
||||
LockRotationZ: false
|
||||
BoxColliderComponent:
|
||||
Offset: [0, 0, 0]
|
||||
Size: [2, 2, 2]
|
||||
IsTrigger: false
|
||||
Material: 0
|
||||
MaterialPath: ""
|
||||
- Entity: 8234256119181302872
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [1.736814, 1.4724115, -7.9285727]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
MeshComponent:
|
||||
AssetID: 14957733959243172548
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
Materials:
|
||||
Slot 0:
|
||||
AssetHandle: 0
|
||||
AssetPath: ""
|
||||
RigidBodyComponent:
|
||||
BodyType: 1
|
||||
Mass: 1
|
||||
LinearDrag: 0
|
||||
AngularDrag: 0.05
|
||||
DisableGravity: false
|
||||
IsKinematic: false
|
||||
Layer: 0
|
||||
Constraints:
|
||||
LockPositionX: false
|
||||
LockPositionY: false
|
||||
LockPositionZ: false
|
||||
LockRotationX: false
|
||||
LockRotationY: false
|
||||
LockRotationZ: false
|
||||
BoxColliderComponent:
|
||||
Offset: [0, 0, 0]
|
||||
Size: [2, 2, 2]
|
||||
IsTrigger: false
|
||||
Material: 0
|
||||
MaterialPath: ""
|
||||
- Entity: 5834225236589765516
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [-2.6417403, 1.4724115, -7.9285727]
|
||||
Rotation: [0.52199936, 0, 0]
|
||||
Scale: [1, 1.0000001, 1.0000001]
|
||||
MeshComponent:
|
||||
AssetID: 14957733959243172548
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
Materials:
|
||||
Slot 0:
|
||||
AssetHandle: 0
|
||||
AssetPath: ""
|
||||
RigidBodyComponent:
|
||||
BodyType: 1
|
||||
Mass: 1
|
||||
LinearDrag: 0
|
||||
AngularDrag: 0.05
|
||||
DisableGravity: false
|
||||
IsKinematic: false
|
||||
Layer: 0
|
||||
Constraints:
|
||||
LockPositionX: false
|
||||
LockPositionY: false
|
||||
LockPositionZ: false
|
||||
LockRotationX: false
|
||||
LockRotationY: false
|
||||
LockRotationZ: false
|
||||
BoxColliderComponent:
|
||||
Offset: [0, 0, 0]
|
||||
Size: [2, 2, 2]
|
||||
IsTrigger: false
|
||||
Material: 0
|
||||
MaterialPath: ""
|
||||
- Entity: 8293051279669100759
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [1.736814, 1.4724115, -4.2181306]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
MeshComponent:
|
||||
AssetID: 14957733959243172548
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
Materials:
|
||||
Slot 0:
|
||||
AssetHandle: 0
|
||||
AssetPath: ""
|
||||
RigidBodyComponent:
|
||||
BodyType: 1
|
||||
Mass: 1
|
||||
LinearDrag: 0
|
||||
AngularDrag: 0.05
|
||||
DisableGravity: false
|
||||
IsKinematic: false
|
||||
Layer: 0
|
||||
Constraints:
|
||||
LockPositionX: false
|
||||
LockPositionY: false
|
||||
LockPositionZ: false
|
||||
LockRotationX: false
|
||||
LockRotationY: false
|
||||
LockRotationZ: false
|
||||
BoxColliderComponent:
|
||||
Offset: [0, 0, 0]
|
||||
Size: [2, 2, 2]
|
||||
IsTrigger: false
|
||||
Material: 0
|
||||
MaterialPath: ""
|
||||
PhysicsLayers:
|
||||
[]
|
||||
@ -1,11 +1,50 @@
|
||||
Scene: Scene Name
|
||||
Environment:
|
||||
AssetHandle: 10549690553241162923
|
||||
Light:
|
||||
Direction: [-0.314, -0.941, -0.209]
|
||||
Radiance: [0, 0, 0]
|
||||
Multiplier: 1
|
||||
AssetHandle: 6095149963749185931
|
||||
Entities:
|
||||
- Entity: 6421668200759325475
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: M1911Materials
|
||||
TransformComponent:
|
||||
Position: [0, 3.159583, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
MeshComponent:
|
||||
AssetID: 7219694555758922702
|
||||
AssetPath: assets/models/m1911/M1911Materials.fbx
|
||||
- Entity: 16992665426857995732
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [0, 0, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [50, 1, 50]
|
||||
MeshComponent:
|
||||
AssetID: 18328012085543462741
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
- Entity: 18182275256052989728
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Sky Light
|
||||
TransformComponent:
|
||||
Position: [0, 0, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
SkyLightComponent:
|
||||
EnvironmentMap: 6095149963749185931
|
||||
EnvironmentAssetPath: ""
|
||||
Intensity: 1
|
||||
Angle: 0
|
||||
DynamicSky: true
|
||||
TurbidityAzimuthInclination: [2, 0.15, 0.71]
|
||||
- Entity: 17803125207910630398
|
||||
Parent: 0
|
||||
Children:
|
||||
@ -20,30 +59,6 @@ Entities:
|
||||
Radiance: [1, 1, 1]
|
||||
CastShadows: true
|
||||
SoftShadows: true
|
||||
LightSize: 0.5
|
||||
- Entity: 4315886439647742331
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [0, 2.048974, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
MeshComponent:
|
||||
AssetID: 3580169978473467053
|
||||
- Entity: 16992665426857995732
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [0, 0, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [50, 1, 50]
|
||||
MeshComponent:
|
||||
AssetID: 3580169978473467053
|
||||
LightSize: 0.9
|
||||
PhysicsLayers:
|
||||
[]
|
||||
@ -1,12 +1,21 @@
|
||||
Scene: Scene Name
|
||||
Environment:
|
||||
AssetHandle: 17073147362577408906
|
||||
Light:
|
||||
Direction: [-0.314, -0.941, -0.209]
|
||||
Radiance: [0, 0, 0]
|
||||
Multiplier: 1
|
||||
AssetHandle: 5211537204242875091
|
||||
Entities:
|
||||
- Entity: 3696833073589069488
|
||||
- Entity: 15706224176559717512
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
TagComponent:
|
||||
Tag: Cube
|
||||
TransformComponent:
|
||||
Position: [0, 0, 0]
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
MeshComponent:
|
||||
AssetID: 18328012085543462741
|
||||
AssetPath: assets/meshes/Default/Cube.fbx
|
||||
- Entity: 8041206185299282567
|
||||
Parent: 0
|
||||
Children:
|
||||
[]
|
||||
@ -17,8 +26,11 @@ Entities:
|
||||
Rotation: [0, 0, 0]
|
||||
Scale: [1, 1, 1]
|
||||
SkyLightComponent:
|
||||
EnvironmentMap: 17073147362577408906
|
||||
EnvironmentMap: 5211537204242875091
|
||||
EnvironmentAssetPath: assets/env/venice_dawn_1_4k.hdr
|
||||
Intensity: 1
|
||||
Angle: 0
|
||||
DynamicSky: false
|
||||
TurbidityAzimuthInclination: [2, 0, 0]
|
||||
PhysicsLayers:
|
||||
[]
|
||||
@ -24,16 +24,16 @@ uniform sampler2D u_Texture;
|
||||
uniform bool u_Horizontal; // 未使用,可保留或移除
|
||||
uniform bool u_FirstPass; // 是否进行阈值处理
|
||||
uniform float u_Threshold; // 亮度阈值
|
||||
uniform int u_Quality;
|
||||
uniform float u_Directions; // 模糊方向数
|
||||
uniform float u_Size; // 模糊半径
|
||||
|
||||
void main()
|
||||
{
|
||||
float Pi = 6.28318530718; // 2*PI
|
||||
|
||||
float Directions = 32.0; // 模糊方向数
|
||||
float Quality = 6.0; // 每个方向上的采样质量(采样次数)
|
||||
float Size = 16.0; // 模糊半径
|
||||
|
||||
vec2 Radius = u_Size / textureSize(u_Texture, 0);
|
||||
vec2 Radius = Size / textureSize(u_Texture, 0);
|
||||
|
||||
// 中心像素采样
|
||||
vec3 centerColor = texture(u_Texture, v_TexCoord).rgb;
|
||||
@ -50,9 +50,9 @@ void main()
|
||||
float totalSamples = 1.0; // 有效采样计数(中心像素已计入)
|
||||
|
||||
// 周围像素采样
|
||||
for (float d = 0.0; d < Pi; d += Pi / u_Directions)
|
||||
for (float d = 0.0; d < Pi; d += Pi / Directions)
|
||||
{
|
||||
for (float i = 1.0 / u_Quality; i <= 1.0; i += 1.0 / u_Quality)
|
||||
for (float i = 1.0 / Quality; i <= 1.0; i += 1.0 / Quality)
|
||||
{
|
||||
vec2 offset = vec2(cos(d), sin(d)) * Radius * i;
|
||||
vec3 sampleColor = texture(u_Texture, v_TexCoord + offset).rgb;
|
||||
|
||||
@ -107,16 +107,16 @@ void main(void)
|
||||
if(gl_GlobalInvocationID.x >= outputSize.x || gl_GlobalInvocationID.y >= outputSize.y) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Solid angle associated with a single cubemap texel at zero mipmap level.
|
||||
// This will come in handy for importance sampling below.
|
||||
vec2 inputSize = vec2(textureSize(inputTexture, 0));
|
||||
float wt = 4.0 * PI / (6 * inputSize.x * inputSize.y);
|
||||
|
||||
|
||||
// Approximation: Assume zero viewing angle (isotropic reflections).
|
||||
vec3 N = GetCubeMapTexCoord();
|
||||
vec3 Lo = N;
|
||||
|
||||
|
||||
vec3 S, T;
|
||||
computeBasisVectors(N, S, T);
|
||||
|
||||
|
||||
@ -1,348 +0,0 @@
|
||||
#type vertex
|
||||
#version 430 core
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
|
||||
out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
v_TexCoord = a_TexCoord;
|
||||
gl_Position = vec4(a_Position.xy, 0.0, 1.0);
|
||||
}
|
||||
|
||||
|
||||
#type fragment
|
||||
#version 430 core
|
||||
|
||||
// ==================== 输入 ====================
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
// G-buffer 纹理
|
||||
uniform sampler2D u_AlbedoMetallic; // RGB: albedo, A: metallic
|
||||
uniform sampler2D u_NormalRoughness; // RGB: normal (encoded), A: roughness
|
||||
uniform sampler2D u_EmissiveAO; // RGB: emissive, A: AO
|
||||
uniform sampler2D u_Depth; // depth
|
||||
|
||||
// 相机参数
|
||||
uniform mat4 u_InvViewProj; // 逆视图投影矩阵,用于重建世界坐标
|
||||
uniform vec3 u_CameraPosition;
|
||||
|
||||
// 光源结构体(与你的PBR着色器一致)
|
||||
struct DirectionalLight {
|
||||
vec3 Direction;
|
||||
vec3 Radiance;
|
||||
float Intensity;
|
||||
bool CastShadows;
|
||||
};
|
||||
struct PointLight {
|
||||
vec3 Position;
|
||||
vec3 Radiance;
|
||||
float Intensity;
|
||||
float Range;
|
||||
bool CastShadows;
|
||||
};
|
||||
struct SpotLight {
|
||||
vec3 Position;
|
||||
vec3 Direction;
|
||||
vec3 Radiance;
|
||||
float Intensity;
|
||||
float Range;
|
||||
float InnerConeCos;
|
||||
float OuterConeCos;
|
||||
bool CastShadows;
|
||||
};
|
||||
|
||||
uniform DirectionalLight u_DirectionalLights; // 仅一个方向光
|
||||
uniform int u_PointLightCount;
|
||||
uniform PointLight u_PointLights[16]; // 假设最多16个点光源
|
||||
uniform int u_SpotLightCount;
|
||||
uniform SpotLight u_SpotLights[16]; // 最多16个聚光源
|
||||
|
||||
// IBL 相关
|
||||
uniform samplerCube u_EnvRadianceTex;
|
||||
uniform samplerCube u_EnvIrradianceTex;
|
||||
uniform sampler2D u_BRDFLUTTexture;
|
||||
uniform float u_IBLContribution;
|
||||
uniform float u_EnvMapRotation;
|
||||
|
||||
// 阴影相关
|
||||
uniform sampler2D u_ShadowMap;
|
||||
uniform float u_ShadowBias;
|
||||
uniform float u_ShadowSoftness;
|
||||
uniform int u_ShadowEnabled;
|
||||
uniform float u_ShadowIntensity; // 阴影强度(0-1)
|
||||
uniform mat4 u_LightSpaceMatrix; // 方向光光源空间矩阵
|
||||
|
||||
// 天空盒(可选)
|
||||
uniform samplerCube u_Skybox; // 如果深度为1.0则采样天空盒
|
||||
uniform float u_SkyIntensity;
|
||||
uniform float u_SkyTextureLod;
|
||||
|
||||
// 输出
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
// ==================== 常量 ====================
|
||||
const float PI = 3.14159265359;
|
||||
const float Epsilon = 0.00001;
|
||||
const vec3 Fdielectric = vec3(0.04);
|
||||
|
||||
|
||||
// ==================== 工具函数 ====================
|
||||
// 从深度重建世界坐标
|
||||
vec3 worldPosFromDepth(vec2 uv, float depth) {
|
||||
vec4 clipPos = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
vec4 worldPos = u_InvViewProj * clipPos;
|
||||
return worldPos.xyz / worldPos.w;
|
||||
}
|
||||
|
||||
// 从深度重建世界空间方向(用于天空盒采样)
|
||||
vec3 worldDirFromUV(vec2 uv) {
|
||||
// 假设深度为1.0时,得到远平面方向
|
||||
vec4 clipPos = vec4(uv * 2.0 - 1.0, 1.0, 1.0);
|
||||
vec4 worldPos = u_InvViewProj * clipPos;
|
||||
return normalize(worldPos.xyz / worldPos.w);
|
||||
}
|
||||
|
||||
// 旋转向量(绕Y轴)
|
||||
vec3 RotateVectorAboutY(float angle, vec3 vec) {
|
||||
angle = radians(angle);
|
||||
mat3 rotationMatrix = mat3(
|
||||
vec3(cos(angle), 0.0, sin(angle)),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(-sin(angle), 0.0, cos(angle))
|
||||
);
|
||||
return rotationMatrix * vec;
|
||||
}
|
||||
|
||||
// ==================== PBR 函数(复用你的代码) ====================
|
||||
float ndfGGX(float cosLh, float roughness) {
|
||||
float alpha = roughness * roughness;
|
||||
float alphaSq = alpha * alpha;
|
||||
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||
return alphaSq / (PI * denom * denom);
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness) {
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
float nom = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
return nom / denom;
|
||||
}
|
||||
|
||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
vec3 fresnelSchlick(vec3 F0, float cosTheta) {
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness) {
|
||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
// ---------- 方向光 ----------
|
||||
vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic) {
|
||||
vec3 L = normalize(-light.Direction);
|
||||
vec3 Lradiance = light.Radiance * light.Intensity;
|
||||
|
||||
vec3 Lh = normalize(L + V);
|
||||
float cosLi = max(dot(N, L), 0.0);
|
||||
float cosLh = max(dot(N, Lh), 0.0);
|
||||
|
||||
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
|
||||
float D = ndfGGX(cosLh, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - metallic);
|
||||
vec3 diffuseBRDF = kd * albedo;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||
}
|
||||
|
||||
// ---------- 点光源 ----------
|
||||
vec3 ComputePointLight(PointLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic, vec3 worldPos) {
|
||||
vec3 lightVec = light.Position - worldPos;
|
||||
float dist = length(lightVec);
|
||||
if (dist > light.Range) return vec3(0.0);
|
||||
|
||||
vec3 L = lightVec / dist;
|
||||
vec3 Lradiance = light.Radiance * light.Intensity;
|
||||
|
||||
float attenuation = 1.0 / (dist * dist + 0.0001);
|
||||
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
|
||||
rangeFactor = rangeFactor * rangeFactor;
|
||||
attenuation *= rangeFactor;
|
||||
|
||||
vec3 Lh = normalize(L + V);
|
||||
float cosLi = max(dot(N, L), 0.0);
|
||||
float cosLh = max(dot(N, Lh), 0.0);
|
||||
|
||||
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
|
||||
float D = ndfGGX(cosLh, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - metallic);
|
||||
vec3 diffuseBRDF = kd * albedo;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
||||
}
|
||||
|
||||
// ---------- 聚光源 ----------
|
||||
vec3 ComputeSpotLight(SpotLight light, vec3 F0, vec3 N, vec3 V, float NdotV, vec3 albedo, float roughness, float metallic, vec3 worldPos) {
|
||||
vec3 lightVec = light.Position - worldPos;
|
||||
float dist = length(lightVec);
|
||||
if (dist > light.Range) return vec3(0.0);
|
||||
|
||||
vec3 L = lightVec / dist;
|
||||
vec3 Lradiance = light.Radiance * light.Intensity;
|
||||
|
||||
float attenuation = 1.0 / (dist * dist + 0.0001);
|
||||
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
|
||||
rangeFactor = rangeFactor * rangeFactor;
|
||||
attenuation *= rangeFactor;
|
||||
|
||||
float cosAngle = dot(-L, normalize(light.Direction));
|
||||
if (cosAngle < light.OuterConeCos) return vec3(0.0);
|
||||
float angleFalloff = (cosAngle - light.OuterConeCos) / (light.InnerConeCos - light.OuterConeCos);
|
||||
angleFalloff = clamp(angleFalloff, 0.0, 1.0);
|
||||
attenuation *= angleFalloff;
|
||||
|
||||
vec3 Lh = normalize(L + V);
|
||||
float cosLi = max(dot(N, L), 0.0);
|
||||
float cosLh = max(dot(N, Lh), 0.0);
|
||||
|
||||
vec3 F = fresnelSchlick(F0, max(dot(Lh, V), 0.0));
|
||||
float D = ndfGGX(cosLh, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - metallic);
|
||||
vec3 diffuseBRDF = kd * albedo;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
||||
}
|
||||
|
||||
// ---------- IBL ----------
|
||||
vec3 IBL(vec3 F0, vec3 N, vec3 V, float NdotV, float roughness, float metallic, vec3 albedo) {
|
||||
vec3 irradiance = texture(u_EnvIrradianceTex, N).rgb;
|
||||
vec3 F = fresnelSchlickRoughness(F0, NdotV, roughness);
|
||||
vec3 kd = (1.0 - F) * (1.0 - metallic);
|
||||
vec3 diffuseIBL = albedo * irradiance;
|
||||
|
||||
vec3 R = 2.0 * NdotV * N - V; // 反射向量
|
||||
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
||||
vec3 specularIrradiance = textureLod(
|
||||
u_EnvRadianceTex,
|
||||
RotateVectorAboutY(u_EnvMapRotation, R),
|
||||
roughness * u_EnvRadianceTexLevels
|
||||
).rgb;
|
||||
|
||||
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(NdotV, 1.0 - roughness)).rg;
|
||||
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
||||
|
||||
return kd * diffuseIBL + specularIBL;
|
||||
}
|
||||
|
||||
// ---------- 阴影 ----------
|
||||
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir) {
|
||||
if (u_ShadowEnabled == 0) return 0.0;
|
||||
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||
return 0.0;
|
||||
|
||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
|
||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||
|
||||
float shadow = 0.0;
|
||||
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
||||
int pcfRange = int(u_ShadowSoftness);
|
||||
int sampleCount = 0;
|
||||
|
||||
for (int x = -pcfRange; x <= pcfRange; ++x) {
|
||||
for (int y = -pcfRange; y <= pcfRange; ++y) {
|
||||
float pcfDepth = texture(u_ShadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
|
||||
shadow += (currentDepth - bias > pcfDepth) ? 1.0 : 0.0;
|
||||
sampleCount++;
|
||||
}
|
||||
}
|
||||
shadow /= float(sampleCount);
|
||||
|
||||
return shadow * u_ShadowIntensity; // 应用阴影强度
|
||||
}
|
||||
|
||||
// ==================== 主函数 ====================
|
||||
void main() {
|
||||
vec2 uv = v_TexCoord;
|
||||
float depth = texture(u_Depth, uv).r;
|
||||
|
||||
if (depth >= 1.0) {
|
||||
vec3 dir = worldDirFromUV(uv);
|
||||
vec3 skyColor = textureLod(u_Skybox, dir, u_SkyTextureLod).rgb * u_SkyIntensity;
|
||||
o_Color = vec4(skyColor, 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 albedoMetal = texture(u_AlbedoMetallic, uv);
|
||||
vec4 normalRough = texture(u_NormalRoughness, uv);
|
||||
vec4 emissiveAO = texture(u_EmissiveAO, uv);
|
||||
|
||||
vec3 albedo = albedoMetal.rgb;
|
||||
float metallic = albedoMetal.a;
|
||||
vec3 normal = normalRough.rgb * 2.0 - 1.0;
|
||||
float roughness = normalRough.a;
|
||||
vec3 emissive = emissiveAO.rgb;
|
||||
float ao = emissiveAO.a;
|
||||
|
||||
vec3 worldPos = worldPosFromDepth(uv, depth);
|
||||
vec3 V = normalize(u_CameraPosition - worldPos);
|
||||
float NdotV = clamp(dot(normal, V), 0.0, 1.0);
|
||||
|
||||
vec3 F0 = mix(Fdielectric, albedo, metallic);
|
||||
|
||||
vec3 Lo = vec3(0.0);
|
||||
|
||||
// Direction Light
|
||||
if (u_DirectionalLights.Intensity > 0.0) {
|
||||
Lo += ComputeDirectionalLight(u_DirectionalLights, F0, normal, V, NdotV, albedo, roughness, metallic);
|
||||
}
|
||||
|
||||
// Point Light
|
||||
for (int i = 0; i < u_PointLightCount; ++i) {
|
||||
Lo += ComputePointLight(u_PointLights[i], F0, normal, V, NdotV, albedo, roughness, metallic, worldPos);
|
||||
}
|
||||
|
||||
// Spot light
|
||||
for (int i = 0; i < u_SpotLightCount; ++i) {
|
||||
Lo += ComputeSpotLight(u_SpotLights[i], F0, normal, V, NdotV, albedo, roughness, metallic, worldPos);
|
||||
}
|
||||
|
||||
float shadowFactor = 1.0;
|
||||
if (u_ShadowEnabled > 0 && u_DirectionalLights.CastShadows && u_DirectionalLights.Intensity > 0.0) {
|
||||
vec4 fragPosLightSpace = u_LightSpaceMatrix * vec4(worldPos, 1.0);
|
||||
float shadow = calculateShadow(fragPosLightSpace, normal, u_DirectionalLights.Direction);
|
||||
shadowFactor = 1.0 - shadow;
|
||||
}
|
||||
Lo *= shadowFactor;
|
||||
|
||||
// 计算 IBL
|
||||
vec3 ibl = IBL(F0, normal, V, NdotV, roughness, metallic, albedo) * u_IBLContribution;
|
||||
|
||||
vec3 finalColor = Lo + ibl + emissive;
|
||||
|
||||
o_Color = vec4(finalColor, 1.0);
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
// -----------------------------
|
||||
// -----------------------------
|
||||
// -- Based on Hazel PBR shader --
|
||||
// -----------------------------
|
||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||
@ -28,8 +28,6 @@ uniform mat4 u_ViewProjectionMatrix;
|
||||
uniform mat4 u_ViewMatrix;
|
||||
uniform mat4 u_Transform;
|
||||
|
||||
uniform mat4 u_LightSpaceMatrix;
|
||||
|
||||
out VertexOutput
|
||||
{
|
||||
vec3 WorldPosition;
|
||||
@ -39,7 +37,7 @@ out VertexOutput
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
vec3 ViewPosition;
|
||||
vec4 FragPosLightSpace;
|
||||
float ViewZ;
|
||||
} vs_Output;
|
||||
|
||||
void main()
|
||||
@ -58,9 +56,8 @@ void main()
|
||||
vs_Output.WorldTransform = mat3(u_Transform);
|
||||
vs_Output.Binormal = a_Binormal;
|
||||
|
||||
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * localPosition;
|
||||
|
||||
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
||||
vs_Output.ViewZ = vs_Output.ViewPosition.z;
|
||||
|
||||
// gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
||||
gl_Position = u_ViewProjectionMatrix * u_Transform * localPosition;
|
||||
@ -75,6 +72,10 @@ const float Epsilon = 0.00001;
|
||||
const int LightCount = 1;
|
||||
const vec3 Fdielectric = vec3(0.04);
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
layout(location = 1) out vec4 o_MaterialInfo;
|
||||
layout(location = 2) out vec4 o_BloomColor;
|
||||
|
||||
struct DirectionalLight {
|
||||
vec3 Direction;
|
||||
vec3 Radiance;
|
||||
@ -110,20 +111,18 @@ in VertexOutput
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
vec3 ViewPosition;
|
||||
vec4 FragPosLightSpace;
|
||||
float ViewZ;
|
||||
} vs_Input;
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
layout(location = 1) out vec4 o_BloomColor;
|
||||
|
||||
uniform DirectionalLight u_DirectionalLights;
|
||||
uniform vec3 u_CameraPosition;
|
||||
|
||||
uniform int u_PointLightCount;
|
||||
uniform PointLight u_PointLights;
|
||||
uniform PointLight u_PointLights[8];
|
||||
|
||||
uniform int u_SpotLightCount;
|
||||
uniform SpotLight u_SpotLights;
|
||||
uniform SpotLight u_SpotLights[8];
|
||||
|
||||
|
||||
// PBR
|
||||
@ -144,7 +143,7 @@ uniform float u_BloomThreshold;
|
||||
uniform float u_EnvMapRotation;
|
||||
|
||||
// baseColor
|
||||
uniform vec3 u_AlbedoColor;
|
||||
uniform vec4 u_AlbedoColor;
|
||||
uniform float u_Metalness;
|
||||
uniform float u_Roughness;
|
||||
|
||||
@ -155,22 +154,23 @@ uniform float u_MetalnessTexToggle;
|
||||
uniform float u_RoughnessTexToggle;
|
||||
|
||||
// shadow
|
||||
uniform sampler2D u_ShadowMap;
|
||||
const int CSM_CASCADE_COUNT = 4;
|
||||
uniform sampler2D u_ShadowMap[4];
|
||||
uniform mat4 u_LightSpaceMatrix0;
|
||||
uniform mat4 u_LightSpaceMatrix1;
|
||||
uniform mat4 u_LightSpaceMatrix2;
|
||||
uniform mat4 u_LightSpaceMatrix3;
|
||||
uniform vec4 u_CascadeSplits;
|
||||
uniform float u_ShadowFar;
|
||||
uniform float u_ShadowNear;
|
||||
uniform float u_ShadowBias;
|
||||
uniform float u_ShadowSoftness;
|
||||
uniform float u_ShadowIntensity;
|
||||
uniform int u_ShadowEnabled;
|
||||
|
||||
// Emissive
|
||||
uniform sampler2D u_EmissiveTexture;
|
||||
uniform float u_EmissiveTexToggle;
|
||||
uniform vec3 u_EmissiveColor;
|
||||
uniform float u_EmissiveIntensity;
|
||||
|
||||
|
||||
struct PBRParameters
|
||||
{
|
||||
vec3 Albedo;
|
||||
vec4 Albedo;
|
||||
float Roughness;
|
||||
float Metalness;
|
||||
vec3 Normal;
|
||||
@ -232,7 +232,7 @@ vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, PBRParameters para
|
||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
||||
vec3 diffuseBRDF = kd * params.Albedo;
|
||||
vec3 diffuseBRDF = kd * params.Albedo.rgb;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||
@ -264,7 +264,7 @@ vec3 ComputePointLight(PointLight light, vec3 F0, PBRParameters params, vec3 wor
|
||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
||||
vec3 diffuseBRDF = kd * params.Albedo;
|
||||
vec3 diffuseBRDF = kd * params.Albedo.rgb;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
||||
@ -301,7 +301,7 @@ vec3 ComputeSpotLight(SpotLight light, vec3 F0, PBRParameters params, vec3 world
|
||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
||||
vec3 diffuseBRDF = kd * params.Albedo;
|
||||
vec3 diffuseBRDF = kd * params.Albedo.rgb;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
||||
@ -326,7 +326,7 @@ vec3 Lighting(vec3 F0)
|
||||
float G = GeometrySmith(m_Params.Normal, m_Params.View, Li, m_Params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||
vec3 diffuseBRDF = kd * m_Params.Albedo;
|
||||
vec3 diffuseBRDF = kd * m_Params.Albedo.rgb;
|
||||
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * m_Params.NdotV);
|
||||
|
||||
@ -352,7 +352,7 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
||||
vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
|
||||
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
|
||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||
vec3 diffuseIBL = m_Params.Albedo * irradiance;
|
||||
vec3 diffuseIBL = m_Params.Albedo.rgb * irradiance;
|
||||
|
||||
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
||||
vec3 specularIrradiance = textureLod(
|
||||
@ -368,80 +368,119 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
||||
}
|
||||
|
||||
// shadow
|
||||
|
||||
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
||||
int selectCascade(float viewZ)
|
||||
{
|
||||
// Perspective divide
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
|
||||
// Transform to [0,1] range
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
// If outside shadow map bounds, assume no shadow
|
||||
if(projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||
return 0.0;
|
||||
|
||||
// Get closest depth value from light's perspective
|
||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
|
||||
// Calculate bias based on surface angle
|
||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||
|
||||
// PCF (Percentage Closer Filtering) for soft shadows
|
||||
float shadow = 0.0;
|
||||
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
||||
int pcfRange = int(u_ShadowSoftness);
|
||||
int sampleCount = 0;
|
||||
|
||||
for(int x = -pcfRange; x <= pcfRange; ++x)
|
||||
{
|
||||
for(int y = -pcfRange; y <= pcfRange; ++y)
|
||||
{
|
||||
float pcfDepth = texture(u_ShadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
|
||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
||||
sampleCount++;
|
||||
}
|
||||
}
|
||||
shadow /= float(sampleCount);
|
||||
|
||||
return shadow;
|
||||
float depth = -viewZ;
|
||||
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||
if (linearDepth < u_CascadeSplits.x) return 0;
|
||||
if (linearDepth < u_CascadeSplits.y) return 1;
|
||||
if (linearDepth < u_CascadeSplits.z) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
||||
mat4 getLightSpaceMatrix(int cascade)
|
||||
{
|
||||
if (u_ShadowEnabled == 0) return 1.0;
|
||||
if (cascade == 0) return u_LightSpaceMatrix0;
|
||||
else if (cascade == 1) return u_LightSpaceMatrix1;
|
||||
else if (cascade == 2) return u_LightSpaceMatrix2;
|
||||
else return u_LightSpaceMatrix3;
|
||||
}
|
||||
|
||||
float getCascadeSplit(int cascade)
|
||||
{
|
||||
if (cascade == 0) return u_CascadeSplits.x;
|
||||
else if (cascade == 1) return u_CascadeSplits.y;
|
||||
else if (cascade == 2) return u_CascadeSplits.z;
|
||||
else return u_CascadeSplits.w;
|
||||
}
|
||||
|
||||
float sampleShadow(int cascade, vec2 uv, float compareDepth, float bias)
|
||||
{
|
||||
float depth;
|
||||
if (cascade == 0) depth = texture(u_ShadowMap[0], uv).r;
|
||||
else if (cascade == 1) depth = texture(u_ShadowMap[1], uv).r;
|
||||
else if (cascade == 2) depth = texture(u_ShadowMap[2], uv).r;
|
||||
else depth = texture(u_ShadowMap[3], uv).r;
|
||||
return (compareDepth - bias) > depth ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
vec2 getTexelSize(int cascade)
|
||||
{
|
||||
if (cascade == 0) return 1.0 / vec2(textureSize(u_ShadowMap[0], 0));
|
||||
else if (cascade == 1) return 1.0 / vec2(textureSize(u_ShadowMap[1], 0));
|
||||
else if (cascade == 2) return 1.0 / vec2(textureSize(u_ShadowMap[2], 0));
|
||||
else return 1.0 / vec2(textureSize(u_ShadowMap[3], 0));
|
||||
}
|
||||
|
||||
float pcfShadow(int cascade, vec3 projCoords, float bias)
|
||||
{
|
||||
vec2 texelSize = getTexelSize(cascade);
|
||||
int pcfRange = clamp(int(u_ShadowSoftness), 0, 3);
|
||||
float shadow = 0.0;
|
||||
int samples = 0;
|
||||
|
||||
for (int x = -pcfRange; x <= pcfRange; ++x)
|
||||
{
|
||||
for (int y = -pcfRange; y <= pcfRange; ++y)
|
||||
{
|
||||
vec2 offset = vec2(x, y) * texelSize;
|
||||
shadow += sampleShadow(cascade, projCoords.xy + offset, projCoords.z, bias);
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
return shadow / float(samples);
|
||||
}
|
||||
|
||||
float calculateCSMShadow(vec3 worldPos, vec3 normal, vec3 lightDir, float viewZ)
|
||||
{
|
||||
int cascade = selectCascade(viewZ);
|
||||
|
||||
vec4 fragPosLightSpace = getLightSpaceMatrix(cascade) * vec4(worldPos, 1.0);
|
||||
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
||||
projCoords.z > 1.0) return 1.0;
|
||||
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||
projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||
return 0.0;
|
||||
|
||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||
float shadow = pcfShadow(cascade, projCoords, bias);
|
||||
|
||||
float bias = max(u_ShadowBias * (1.0 - NdotL), u_ShadowBias * 0.5);
|
||||
float cascadeEdge = 0.0;
|
||||
if (cascade < CSM_CASCADE_COUNT - 1)
|
||||
{
|
||||
float depth = -viewZ;
|
||||
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||
float splitDist = getCascadeSplit(cascade);
|
||||
float prevSplit = (cascade > 0) ? getCascadeSplit(cascade - 1) : 0.0;
|
||||
float blendStart = splitDist - (splitDist - prevSplit) * 0.1;
|
||||
if (linearDepth > blendStart)
|
||||
{
|
||||
cascadeEdge = (linearDepth - blendStart) / (splitDist - blendStart);
|
||||
|
||||
float shadow = (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
|
||||
return mix(1.0, 1.0 - u_ShadowIntensity, shadow);
|
||||
int nextCascade = cascade + 1;
|
||||
vec4 fragPosNext = getLightSpaceMatrix(nextCascade) * vec4(worldPos, 1.0);
|
||||
|
||||
vec3 projCoordsNext = fragPosNext.xyz / fragPosNext.w;
|
||||
projCoordsNext = projCoordsNext * 0.5 + 0.5;
|
||||
|
||||
if (!(projCoordsNext.z > 1.0 || projCoordsNext.x < 0.0 || projCoordsNext.x > 1.0 ||
|
||||
projCoordsNext.y < 0.0 || projCoordsNext.y > 1.0))
|
||||
{
|
||||
float nextShadow = pcfShadow(nextCascade, projCoordsNext, bias);
|
||||
shadow = mix(shadow, nextShadow, cascadeEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shadow * u_ShadowIntensity;
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
float alpha = 1.0;
|
||||
if (u_AlbedoTexToggle > 0.5) {
|
||||
vec4 albedoWithAlpha = texture(u_AlbedoTexture, vs_Input.TexCoord);
|
||||
m_Params.Albedo = albedoWithAlpha.rgb;
|
||||
alpha = albedoWithAlpha.a;
|
||||
} else {
|
||||
m_Params.Albedo = u_AlbedoColor;
|
||||
alpha = 1.0;
|
||||
}
|
||||
|
||||
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord) : u_AlbedoColor;
|
||||
m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
||||
m_Params.Roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
||||
m_Params.Roughness = max(m_Params.Roughness, 0.05);
|
||||
@ -459,11 +498,11 @@ void main()
|
||||
|
||||
vec3 Lr = 2.0 * m_Params.NdotV * m_Params.Normal - m_Params.View;
|
||||
|
||||
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
||||
vec3 F0 = mix(Fdielectric, m_Params.Albedo.rgb, m_Params.Metalness);
|
||||
|
||||
float shadowFactor = 1.0;
|
||||
if (u_ShadowEnabled > 0.5) {
|
||||
float shadow = calculateShadow(vs_Input.FragPosLightSpace, m_Params.Normal, u_DirectionalLights.Direction);
|
||||
float shadow = calculateCSMShadow(vs_Input.WorldPosition, m_Params.Normal, u_DirectionalLights.Direction, vs_Input.ViewZ);
|
||||
shadowFactor = 1.0 - shadow;
|
||||
}
|
||||
|
||||
@ -471,26 +510,27 @@ void main()
|
||||
vec3 lightContribution = u_DirectionalLights.Intensity > 0.0 ? Lighting(F0) * shadowFactor : vec3(0.0);
|
||||
|
||||
if(u_PointLightCount > 0)
|
||||
lightContribution += ComputePointLight(u_PointLights, F0, m_Params, vs_Input.WorldPosition);
|
||||
{
|
||||
for( int i = 0; i < u_PointLightCount; i ++) {
|
||||
lightContribution += ComputePointLight(u_PointLights[i], F0, m_Params, vs_Input.WorldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
if(u_SpotLightCount > 0)
|
||||
lightContribution += ComputeSpotLight(u_SpotLights, F0, m_Params, vs_Input.WorldPosition);
|
||||
|
||||
{
|
||||
for(int i = 0; i < u_SpotLightCount; i ++)
|
||||
{
|
||||
lightContribution += ComputeSpotLight(u_SpotLights[i], F0, m_Params, vs_Input.WorldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
|
||||
|
||||
vec3 emissive = u_EmissiveColor;
|
||||
if (u_EmissiveTexToggle > 0.5) {
|
||||
emissive = texture(u_EmissiveTexture, vs_Input.TexCoord).rgb;
|
||||
}
|
||||
emissive *= u_EmissiveIntensity;
|
||||
|
||||
vec3 finalRGB = lightContribution + iblContribution + emissive;
|
||||
vec4 finalColor = vec4(finalRGB, alpha);
|
||||
|
||||
color = finalColor;
|
||||
color = vec4(lightContribution + iblContribution, 1.0);
|
||||
|
||||
// Bloom
|
||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
o_MaterialInfo = vec4(m_Params.Metalness, m_Params.Roughness, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// -----------------------------
|
||||
// -----------------------------
|
||||
// -- Based on Hazel PBR shader --
|
||||
// -----------------------------
|
||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||
@ -22,8 +22,6 @@ uniform mat4 u_ViewProjectionMatrix;
|
||||
uniform mat4 u_ViewMatrix;
|
||||
uniform mat4 u_Transform;
|
||||
|
||||
uniform mat4 u_LightSpaceMatrix;
|
||||
|
||||
out VertexOutput
|
||||
{
|
||||
vec3 WorldPosition;
|
||||
@ -33,7 +31,7 @@ out VertexOutput
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
vec3 ViewPosition;
|
||||
vec4 FragPosLightSpace;
|
||||
float ViewZ;
|
||||
} vs_Output;
|
||||
|
||||
void main()
|
||||
@ -45,9 +43,8 @@ void main()
|
||||
vs_Output.WorldTransform = mat3(u_Transform);
|
||||
vs_Output.Binormal = a_Binormal;
|
||||
|
||||
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * vec4(a_Position, 1.0);
|
||||
|
||||
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
||||
vs_Output.ViewZ = vs_Output.ViewPosition.z;
|
||||
|
||||
gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
||||
}
|
||||
@ -55,18 +52,16 @@ void main()
|
||||
#type fragment
|
||||
#version 430 core
|
||||
|
||||
layout(location = 0) out vec4 outAlbedoMetal;
|
||||
layout(location = 1) out vec4 outNormalRoughness;
|
||||
layout(location = 2) out vec4 outEmissiveAO;
|
||||
layout(location = 3) out vec4 outColor;
|
||||
layout(location = 4) out vec4 outBloomColor;
|
||||
|
||||
const float PI = 3.141592;
|
||||
const float Epsilon = 0.00001;
|
||||
|
||||
const int LightCount = 1;
|
||||
const vec3 Fdielectric = vec3(0.04);
|
||||
|
||||
layout(location = 0) out vec4 color;
|
||||
layout(location = 1) out vec4 o_MaterialInfo;
|
||||
layout(location = 2) out vec4 o_BloomColor;
|
||||
|
||||
struct DirectionalLight {
|
||||
vec3 Direction;
|
||||
vec3 Radiance;
|
||||
@ -103,19 +98,16 @@ in VertexOutput
|
||||
mat3 WorldTransform;
|
||||
vec3 Binormal;
|
||||
vec3 ViewPosition;
|
||||
vec4 FragPosLightSpace;
|
||||
float ViewZ;
|
||||
} vs_Input;
|
||||
|
||||
|
||||
uniform bool u_GBufferMode;
|
||||
|
||||
uniform DirectionalLight u_DirectionalLights;
|
||||
|
||||
uniform int u_PointLightCount;
|
||||
uniform PointLight u_PointLights;
|
||||
uniform PointLight u_PointLights[8];
|
||||
|
||||
uniform int u_SpotLightCount;
|
||||
uniform SpotLight u_SpotLights;
|
||||
uniform SpotLight u_SpotLights[8];
|
||||
|
||||
|
||||
uniform vec3 u_CameraPosition;
|
||||
@ -138,7 +130,7 @@ uniform float u_BloomThreshold;
|
||||
uniform float u_EnvMapRotation;
|
||||
|
||||
// baseColor
|
||||
uniform vec3 u_AlbedoColor;
|
||||
uniform vec4 u_AlbedoColor;
|
||||
uniform float u_Metalness;
|
||||
uniform float u_Roughness;
|
||||
|
||||
@ -149,21 +141,23 @@ uniform float u_MetalnessTexToggle;
|
||||
uniform float u_RoughnessTexToggle;
|
||||
|
||||
// shadow
|
||||
uniform sampler2D u_ShadowMap;
|
||||
const int CSM_CASCADE_COUNT = 4;
|
||||
uniform sampler2D u_ShadowMap[4];
|
||||
uniform mat4 u_LightSpaceMatrix0;
|
||||
uniform mat4 u_LightSpaceMatrix1;
|
||||
uniform mat4 u_LightSpaceMatrix2;
|
||||
uniform mat4 u_LightSpaceMatrix3;
|
||||
uniform vec4 u_CascadeSplits;
|
||||
uniform float u_ShadowFar;
|
||||
uniform float u_ShadowNear;
|
||||
uniform float u_ShadowBias;
|
||||
uniform float u_ShadowSoftness;
|
||||
uniform float u_ShadowIntensity;
|
||||
uniform int u_ShadowEnabled;
|
||||
|
||||
// Emissive
|
||||
uniform sampler2D u_EmissiveTexture;
|
||||
uniform float u_EmissiveTexToggle;
|
||||
uniform vec3 u_EmissiveColor;
|
||||
uniform float u_EmissiveIntensity;
|
||||
|
||||
struct PBRParameters
|
||||
{
|
||||
vec3 Albedo;
|
||||
vec4 Albedo;
|
||||
float Roughness;
|
||||
float Metalness;
|
||||
vec3 Normal;
|
||||
@ -225,7 +219,7 @@ vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, PBRParameters para
|
||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
||||
vec3 diffuseBRDF = kd * params.Albedo;
|
||||
vec3 diffuseBRDF = kd * params.Albedo.rgb;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||
@ -257,7 +251,7 @@ vec3 ComputePointLight(PointLight light, vec3 F0, PBRParameters params, vec3 wor
|
||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
||||
vec3 diffuseBRDF = kd * params.Albedo;
|
||||
vec3 diffuseBRDF = kd * params.Albedo.rgb;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
||||
@ -294,7 +288,7 @@ vec3 ComputeSpotLight(SpotLight light, vec3 F0, PBRParameters params, vec3 world
|
||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
||||
vec3 diffuseBRDF = kd * params.Albedo;
|
||||
vec3 diffuseBRDF = kd * params.Albedo.rgb;
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
||||
|
||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
||||
@ -317,7 +311,7 @@ vec3 Lighting(vec3 F0)
|
||||
float G = GeometrySmith(m_Params.Normal, m_Params.View, Li, m_Params.Roughness);
|
||||
|
||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||
vec3 diffuseBRDF = kd * m_Params.Albedo;
|
||||
vec3 diffuseBRDF = kd * m_Params.Albedo.rgb;
|
||||
|
||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * m_Params.NdotV);
|
||||
|
||||
@ -343,14 +337,14 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
||||
vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
|
||||
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
|
||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||
vec3 diffuseIBL = m_Params.Albedo * irradiance;
|
||||
vec3 diffuseIBL = m_Params.Albedo.rgb * irradiance;
|
||||
|
||||
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
||||
vec3 specularIrradiance = textureLod(
|
||||
u_EnvRadianceTex,
|
||||
RotateVectorAboutY(u_EnvMapRotation, Lr),
|
||||
m_Params.Roughness * u_EnvRadianceTexLevels
|
||||
).rgb;
|
||||
).rgb;
|
||||
|
||||
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg;
|
||||
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
||||
@ -359,139 +353,172 @@ vec3 IBL(vec3 F0, vec3 Lr)
|
||||
}
|
||||
|
||||
// shadow
|
||||
|
||||
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
||||
int selectCascade(float viewZ)
|
||||
{
|
||||
// Perspective divide
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
|
||||
// Transform to [0,1] range
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
// If outside shadow map bounds, assume no shadow
|
||||
if(projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||
return 0.0;
|
||||
|
||||
// Get closest depth value from light's perspective
|
||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
|
||||
// Calculate bias based on surface angle
|
||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||
|
||||
// PCF (Percentage Closer Filtering) for soft shadows
|
||||
float shadow = 0.0;
|
||||
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
||||
int pcfRange = int(u_ShadowSoftness);
|
||||
int sampleCount = 0;
|
||||
|
||||
for(int x = -pcfRange; x <= pcfRange; ++x)
|
||||
{
|
||||
for(int y = -pcfRange; y <= pcfRange; ++y)
|
||||
{
|
||||
float pcfDepth = texture(u_ShadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
|
||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
||||
sampleCount++;
|
||||
}
|
||||
}
|
||||
shadow /= float(sampleCount);
|
||||
|
||||
return shadow;
|
||||
float depth = -viewZ;
|
||||
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||
if (linearDepth < u_CascadeSplits.x) return 0;
|
||||
if (linearDepth < u_CascadeSplits.y) return 1;
|
||||
if (linearDepth < u_CascadeSplits.z) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
||||
mat4 getLightSpaceMatrix(int cascade)
|
||||
{
|
||||
if (u_ShadowEnabled == 0) return 1.0;
|
||||
if (cascade == 0) return u_LightSpaceMatrix0;
|
||||
else if (cascade == 1) return u_LightSpaceMatrix1;
|
||||
else if (cascade == 2) return u_LightSpaceMatrix2;
|
||||
else return u_LightSpaceMatrix3;
|
||||
}
|
||||
|
||||
float getCascadeSplit(int cascade)
|
||||
{
|
||||
if (cascade == 0) return u_CascadeSplits.x;
|
||||
else if (cascade == 1) return u_CascadeSplits.y;
|
||||
else if (cascade == 2) return u_CascadeSplits.z;
|
||||
else return u_CascadeSplits.w;
|
||||
}
|
||||
|
||||
float sampleShadow(int cascade, vec2 uv, float compareDepth, float bias)
|
||||
{
|
||||
float depth;
|
||||
if (cascade == 0) depth = texture(u_ShadowMap[0], uv).r;
|
||||
else if (cascade == 1) depth = texture(u_ShadowMap[1], uv).r;
|
||||
else if (cascade == 2) depth = texture(u_ShadowMap[2], uv).r;
|
||||
else depth = texture(u_ShadowMap[3], uv).r;
|
||||
return (compareDepth - bias) > depth ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
vec2 getTexelSize(int cascade)
|
||||
{
|
||||
if (cascade == 0) return 1.0 / vec2(textureSize(u_ShadowMap[0], 0));
|
||||
else if (cascade == 1) return 1.0 / vec2(textureSize(u_ShadowMap[1], 0));
|
||||
else if (cascade == 2) return 1.0 / vec2(textureSize(u_ShadowMap[2], 0));
|
||||
else return 1.0 / vec2(textureSize(u_ShadowMap[3], 0));
|
||||
}
|
||||
|
||||
float pcfShadow(int cascade, vec3 projCoords, float bias)
|
||||
{
|
||||
vec2 texelSize = getTexelSize(cascade);
|
||||
int pcfRange = clamp(int(u_ShadowSoftness), 0, 3);
|
||||
float shadow = 0.0;
|
||||
int samples = 0;
|
||||
|
||||
for (int x = -pcfRange; x <= pcfRange; ++x)
|
||||
{
|
||||
for (int y = -pcfRange; y <= pcfRange; ++y)
|
||||
{
|
||||
vec2 offset = vec2(x, y) * texelSize;
|
||||
shadow += sampleShadow(cascade, projCoords.xy + offset, projCoords.z, bias);
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
return shadow / float(samples);
|
||||
}
|
||||
|
||||
float calculateCSMShadow(vec3 worldPos, vec3 normal, vec3 lightDir, float viewZ)
|
||||
{
|
||||
int cascade = selectCascade(viewZ);
|
||||
|
||||
vec4 fragPosLightSpace = getLightSpaceMatrix(cascade) * vec4(worldPos, 1.0);
|
||||
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
||||
projCoords.z > 1.0) return 1.0;
|
||||
if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
||||
projCoords.y < 0.0 || projCoords.y > 1.0)
|
||||
return 0.0;
|
||||
|
||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
||||
float currentDepth = projCoords.z;
|
||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
||||
float shadow = pcfShadow(cascade, projCoords, bias);
|
||||
|
||||
float bias = max(u_ShadowBias * (1.0 - NdotL), u_ShadowBias * 0.5);
|
||||
float cascadeEdge = 0.0;
|
||||
if (cascade < CSM_CASCADE_COUNT - 1)
|
||||
{
|
||||
float depth = -viewZ;
|
||||
float linearDepth = (depth - u_ShadowNear) / (u_ShadowFar - u_ShadowNear);
|
||||
float splitDist = getCascadeSplit(cascade);
|
||||
float prevSplit = (cascade > 0) ? getCascadeSplit(cascade - 1) : 0.0;
|
||||
float blendStart = splitDist - (splitDist - prevSplit) * 0.1;
|
||||
if (linearDepth > blendStart)
|
||||
{
|
||||
cascadeEdge = (linearDepth - blendStart) / (splitDist - blendStart);
|
||||
|
||||
float shadow = (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
|
||||
return mix(1.0, 1.0 - u_ShadowIntensity, shadow);
|
||||
int nextCascade = cascade + 1;
|
||||
vec4 fragPosNext = getLightSpaceMatrix(nextCascade) * vec4(worldPos, 1.0);
|
||||
|
||||
vec3 projCoordsNext = fragPosNext.xyz / fragPosNext.w;
|
||||
projCoordsNext = projCoordsNext * 0.5 + 0.5;
|
||||
|
||||
if (!(projCoordsNext.z > 1.0 || projCoordsNext.x < 0.0 || projCoordsNext.x > 1.0 ||
|
||||
projCoordsNext.y < 0.0 || projCoordsNext.y > 1.0))
|
||||
{
|
||||
float nextShadow = pcfShadow(nextCascade, projCoordsNext, bias);
|
||||
shadow = mix(shadow, nextShadow, cascadeEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shadow * u_ShadowIntensity;
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
// === 1. 采样基础属性(所有模式都需要) ===
|
||||
vec4 albedoWithAlpha = texture(u_AlbedoTexture, vs_Input.TexCoord);
|
||||
vec3 albedo = u_AlbedoTexToggle > 0.5 ? albedoWithAlpha.rgb : u_AlbedoColor;
|
||||
float alpha = u_AlbedoTexToggle > 0.5 ? albedoWithAlpha.a : 1.0;
|
||||
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord) : u_AlbedoColor;
|
||||
m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
||||
m_Params.Roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
||||
m_Params.Roughness = max(m_Params.Roughness, 0.05);
|
||||
|
||||
float metallic = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
||||
float roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
||||
roughness = max(roughness, 0.05);
|
||||
|
||||
// === 2. 法线计算(世界空间) ===
|
||||
vec3 normal = normalize(vs_Input.Normal);
|
||||
// normal
|
||||
m_Params.Normal = normalize(vs_Input.Normal);
|
||||
if (u_NormalTexToggle > 0.5)
|
||||
{
|
||||
vec3 tangentNormal = texture(u_NormalTexture, vs_Input.TexCoord).rgb * 2.0 - 1.0;
|
||||
normal = normalize(vs_Input.WorldNormals * tangentNormal);
|
||||
m_Params.Normal = normalize(2.0 * texture(u_NormalTexture, vs_Input.TexCoord).rgb - 1.0);
|
||||
m_Params.Normal = normalize(vs_Input.WorldNormals * m_Params.Normal);
|
||||
}
|
||||
|
||||
// === 3. 自发光计算 ===
|
||||
vec3 emissive = u_EmissiveColor;
|
||||
if (u_EmissiveTexToggle > 0.5)
|
||||
emissive = texture(u_EmissiveTexture, vs_Input.TexCoord).rgb;
|
||||
emissive *= u_EmissiveIntensity;
|
||||
|
||||
// === 4. GBuffer 模式:直接输出到多个目标 ===
|
||||
if (u_GBufferMode)
|
||||
{
|
||||
outAlbedoMetal = vec4(albedo, metallic);
|
||||
outNormalRoughness = vec4(normal * 0.5 + 0.5, roughness);
|
||||
outEmissiveAO = vec4(emissive, 1.0); // AO 暂设为 1.0
|
||||
return; // 提前结束
|
||||
}
|
||||
|
||||
// === 5. 非 GBuffer 模式:继续 PBR 光照计算 ===
|
||||
// 填充 PBRParameters
|
||||
m_Params.Albedo = albedo;
|
||||
m_Params.Metalness = metallic;
|
||||
m_Params.Roughness = roughness;
|
||||
m_Params.Normal = normal;
|
||||
m_Params.View = normalize(u_CameraPosition - vs_Input.WorldPosition);
|
||||
m_Params.NdotV = max(dot(m_Params.Normal, m_Params.View), 0.0);
|
||||
|
||||
vec3 Lr = 2.0 * m_Params.NdotV * m_Params.Normal - m_Params.View;
|
||||
|
||||
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
||||
vec3 F0 = mix(Fdielectric, m_Params.Albedo.rgb, m_Params.Metalness);
|
||||
|
||||
// Shadow
|
||||
float shadowFactor = 1.0;
|
||||
if (u_ShadowEnabled > 0.5) {
|
||||
float shadow = calculateShadow(vs_Input.FragPosLightSpace, m_Params.Normal, u_DirectionalLights.Direction);
|
||||
float shadow = calculateCSMShadow(vs_Input.WorldPosition, m_Params.Normal, u_DirectionalLights.Direction, vs_Input.ViewZ);
|
||||
shadowFactor = 1.0 - shadow;
|
||||
}
|
||||
|
||||
// directional light with with shadow
|
||||
vec3 lightContribution = u_DirectionalLights.Intensity > 0.0 ? Lighting(F0) * shadowFactor : vec3(0.0);
|
||||
|
||||
|
||||
if(u_PointLightCount > 0)
|
||||
lightContribution += ComputePointLight(u_PointLights, F0, m_Params, vs_Input.WorldPosition);
|
||||
{
|
||||
for( int i = 0; i < u_PointLightCount; i ++) {
|
||||
lightContribution += ComputePointLight(u_PointLights[i], F0, m_Params, vs_Input.WorldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
if(u_SpotLightCount > 0)
|
||||
lightContribution += ComputeSpotLight(u_SpotLights, F0, m_Params, vs_Input.WorldPosition);
|
||||
{
|
||||
for(int i = 0; i < u_SpotLightCount; i ++)
|
||||
{
|
||||
lightContribution += ComputeSpotLight(u_SpotLights[i], F0, m_Params, vs_Input.WorldPosition);
|
||||
}
|
||||
}
|
||||
|
||||
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
|
||||
|
||||
vec3 finalRGB = lightContribution + iblContribution + emissive;
|
||||
vec4 finalColor = vec4(finalRGB, alpha);
|
||||
|
||||
outColor = finalColor;
|
||||
color = vec4(lightContribution + iblContribution, 1.0);
|
||||
|
||||
// Bloom
|
||||
float brightness = dot(finalColor.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||
outBloomColor = brightness > u_BloomThreshold ? finalColor : vec4(0.0, 0.0, 0.0, 1.0);
|
||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
o_MaterialInfo = vec4(m_Params.Metalness, m_Params.Roughness, 0.0, 1.0);
|
||||
}
|
||||
|
||||
207
Editor/assets/shaders/SSR.glsl
Normal file
207
Editor/assets/shaders/SSR.glsl
Normal file
@ -0,0 +1,207 @@
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
|
||||
out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = vec4(a_Position.xy, 0.0, 1.0);
|
||||
v_TexCoord = a_TexCoord;
|
||||
gl_Position = position;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430
|
||||
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D u_ColorTexture;
|
||||
uniform sampler2D u_DepthTexture;
|
||||
uniform sampler2D u_MaterialInfoTexture;
|
||||
|
||||
uniform mat4 u_Projection;
|
||||
uniform mat4 u_InvProjection;
|
||||
|
||||
uniform vec2 u_ScreenSize;
|
||||
uniform float u_CameraNear;
|
||||
uniform float u_CameraFar;
|
||||
|
||||
uniform int u_Steps = 64;
|
||||
uniform float u_Thickness = 0.5;
|
||||
uniform float u_MaxDistance = 30.0;
|
||||
uniform float u_Intensity = 1.0;
|
||||
|
||||
float LinearizeDepth(float depth)
|
||||
{
|
||||
float z = depth * 2.0 - 1.0;
|
||||
return (2.0 * u_CameraNear * u_CameraFar) / (u_CameraFar + u_CameraNear - z * (u_CameraFar - u_CameraNear));
|
||||
}
|
||||
|
||||
vec3 ReconstructViewPos(vec2 tc, float depth)
|
||||
{
|
||||
float z = depth * 2.0 - 1.0;
|
||||
vec4 clipPos = vec4(tc * 2.0 - 1.0, z, 1.0);
|
||||
vec4 viewPos4 = u_InvProjection * clipPos;
|
||||
return viewPos4.xyz / viewPos4.w;
|
||||
}
|
||||
|
||||
vec3 ReconstructNormalFromDepth(vec2 tc, float depth)
|
||||
{
|
||||
vec2 texelSize = 1.0 / u_ScreenSize;
|
||||
|
||||
vec2 tcL = tc - vec2(texelSize.x, 0.0);
|
||||
vec2 tcR = tc + vec2(texelSize.x, 0.0);
|
||||
vec2 tcB = tc - vec2(0.0, texelSize.y);
|
||||
vec2 tcT = tc + vec2(0.0, texelSize.y);
|
||||
|
||||
float depthL = texture(u_DepthTexture, tcL).r;
|
||||
float depthR = texture(u_DepthTexture, tcR).r;
|
||||
float depthB = texture(u_DepthTexture, tcB).r;
|
||||
float depthT = texture(u_DepthTexture, tcT).r;
|
||||
|
||||
vec3 pL = ReconstructViewPos(tcL, depthL);
|
||||
vec3 pR = ReconstructViewPos(tcR, depthR);
|
||||
vec3 pB = ReconstructViewPos(tcB, depthB);
|
||||
vec3 pT = ReconstructViewPos(tcT, depthT);
|
||||
|
||||
vec3 dx = pR - pL;
|
||||
vec3 dy = pT - pB;
|
||||
|
||||
return normalize(cross(dx, dy));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float depth = texture(u_DepthTexture, v_TexCoord).r;
|
||||
|
||||
if (depth >= 1.0)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 matInfo = texture(u_MaterialInfoTexture, v_TexCoord);
|
||||
float metalness = matInfo.r;
|
||||
float roughness = matInfo.g;
|
||||
|
||||
if (roughness > 0.9)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 viewPos = ReconstructViewPos(v_TexCoord, depth);
|
||||
vec3 normal = ReconstructNormalFromDepth(v_TexCoord, depth);
|
||||
|
||||
vec3 viewDir = normalize(-viewPos);
|
||||
float NdotV = max(dot(normal, viewDir), 0.0);
|
||||
|
||||
vec3 reflectDir = reflect(-viewDir, normal);
|
||||
|
||||
if (dot(reflectDir, normal) < 0.0)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 rayOrigin = viewPos + normal * 0.02;
|
||||
vec3 rayEnd = rayOrigin + reflectDir * u_MaxDistance;
|
||||
|
||||
vec4 p0 = u_Projection * vec4(rayOrigin, 1.0);
|
||||
vec4 p1 = u_Projection * vec4(rayEnd, 1.0);
|
||||
|
||||
float k0 = 1.0 / p0.w;
|
||||
float k1 = 1.0 / p1.w;
|
||||
|
||||
p0.xyz *= k0;
|
||||
p1.xyz *= k1;
|
||||
|
||||
vec3 v0 = rayOrigin * k0;
|
||||
vec3 v1 = rayEnd * k1;
|
||||
|
||||
vec2 s0 = p0.xy * 0.5 + 0.5;
|
||||
vec2 s1 = p1.xy * 0.5 + 0.5;
|
||||
|
||||
vec2 sDelta = s1 - s0;
|
||||
float screenDist = length(sDelta * u_ScreenSize);
|
||||
|
||||
if (screenDist < 1.0)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float divisions = min(screenDist, float(u_Steps));
|
||||
vec3 dV = (v1 - v0) / divisions;
|
||||
float dK = (k1 - k0) / divisions;
|
||||
vec2 dS = sDelta / divisions;
|
||||
|
||||
vec3 curV = v0;
|
||||
float curK = k0;
|
||||
vec2 curS = s0;
|
||||
|
||||
vec2 hitUV = vec2(0.0);
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; i < int(divisions); i++)
|
||||
{
|
||||
curV += dV;
|
||||
curK += dK;
|
||||
curS += dS;
|
||||
|
||||
if (curS.x < 0.0 || curS.x > 1.0 || curS.y < 0.0 || curS.y > 1.0)
|
||||
break;
|
||||
|
||||
float sampleDepth = texture(u_DepthTexture, curS).r;
|
||||
float surfDepth = LinearizeDepth(sampleDepth);
|
||||
float rayDepth = -curV.z / curK;
|
||||
|
||||
float depthDiff = rayDepth - surfDepth;
|
||||
|
||||
if (depthDiff > 0.0 && depthDiff < u_Thickness)
|
||||
{
|
||||
hitUV = curS;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 hitNormal = ReconstructNormalFromDepth(hitUV, texture(u_DepthTexture, hitUV).r);
|
||||
if (dot(hitNormal, -reflectDir) < 0.0)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec3 reflectColor = texture(u_ColorTexture, hitUV).rgb;
|
||||
|
||||
float dist = distance(viewPos, ReconstructViewPos(hitUV, texture(u_DepthTexture, hitUV).r));
|
||||
float fadeFactor = 1.0 - smoothstep(u_MaxDistance * 0.5, u_MaxDistance, dist);
|
||||
|
||||
float edgeFade = 1.0;
|
||||
edgeFade *= smoothstep(0.0, 0.15, hitUV.x);
|
||||
edgeFade *= smoothstep(0.0, 0.15, hitUV.y);
|
||||
edgeFade *= smoothstep(0.0, 0.15, 1.0 - hitUV.x);
|
||||
edgeFade *= smoothstep(0.0, 0.15, 1.0 - hitUV.y);
|
||||
|
||||
vec3 F0 = mix(vec3(0.04), reflectColor, metalness);
|
||||
vec3 Fresnel = F0 + (1.0 - F0) * pow(1.0 - NdotV, 5.0);
|
||||
|
||||
float roughnessFade = 1.0 - roughness * roughness;
|
||||
|
||||
vec3 ssrContrib = reflectColor * Fresnel * fadeFactor * edgeFade * roughnessFade * u_Intensity;
|
||||
float ssrAlpha = length(Fresnel) * fadeFactor * edgeFade * roughnessFade;
|
||||
|
||||
o_Color = vec4(ssrContrib, ssrAlpha);
|
||||
}
|
||||
85
Editor/assets/shaders/SSRBlur.glsl
Normal file
85
Editor/assets/shaders/SSRBlur.glsl
Normal file
@ -0,0 +1,85 @@
|
||||
#type vertex
|
||||
#version 430
|
||||
|
||||
layout(location = 0) in vec3 a_Position;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
|
||||
out vec2 v_TexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 position = vec4(a_Position.xy, 0.0, 1.0);
|
||||
v_TexCoord = a_TexCoord;
|
||||
gl_Position = position;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 430
|
||||
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D u_SSRTexture;
|
||||
uniform sampler2D u_DepthTexture;
|
||||
uniform sampler2D u_MaterialInfoTexture;
|
||||
|
||||
uniform vec2 u_ScreenSize;
|
||||
uniform float u_BlurRadius = 4.0;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 texelSize = 1.0 / u_ScreenSize;
|
||||
|
||||
vec4 center = texture(u_SSRTexture, v_TexCoord);
|
||||
if (center.a <= 0.001)
|
||||
{
|
||||
o_Color = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float roughness = texture(u_MaterialInfoTexture, v_TexCoord).g;
|
||||
float effectiveBlurRadius = max(u_BlurRadius * roughness * roughness, 1.0);
|
||||
|
||||
float centerDepth = texture(u_DepthTexture, v_TexCoord).r;
|
||||
vec3 result = vec3(0.0);
|
||||
float totalWeight = 0.0;
|
||||
|
||||
const int kRadius = 6;
|
||||
float sigma = effectiveBlurRadius * 0.5;
|
||||
|
||||
for (int x = -kRadius; x <= kRadius; x++)
|
||||
{
|
||||
for (int y = -kRadius; y <= kRadius; y++)
|
||||
{
|
||||
vec2 offset = vec2(float(x), float(y)) * texelSize * effectiveBlurRadius / float(kRadius);
|
||||
vec2 sampleUV = v_TexCoord + offset;
|
||||
|
||||
if (sampleUV.x < 0.0 || sampleUV.x > 1.0 || sampleUV.y < 0.0 || sampleUV.y > 1.0)
|
||||
continue;
|
||||
|
||||
float sampleDepth = texture(u_DepthTexture, sampleUV).r;
|
||||
float depthDiff = abs(centerDepth - sampleDepth);
|
||||
|
||||
float depthWeight = exp(-depthDiff * 200.0);
|
||||
|
||||
float spatialWeight = exp(-(float(x * x + y * y)) / (2.0 * sigma * sigma));
|
||||
|
||||
vec4 sampleColor = texture(u_SSRTexture, sampleUV);
|
||||
|
||||
float alphaWeight = sampleColor.a > 0.01 ? 1.0 : 0.0;
|
||||
|
||||
float weight = spatialWeight * depthWeight * alphaWeight;
|
||||
|
||||
result += sampleColor.rgb * weight;
|
||||
totalWeight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalWeight > 0.0)
|
||||
result /= totalWeight;
|
||||
else
|
||||
result = center.rgb;
|
||||
|
||||
o_Color = vec4(result, center.a);
|
||||
}
|
||||
@ -17,11 +17,25 @@ void main()
|
||||
#version 430
|
||||
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
layout(location = 1) out vec4 o_BloomTexture;
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D u_HDRTexture; // 来自 LightingPass 的 HDR 颜色
|
||||
uniform sampler2D u_BloomTexture; // 来自 BloomBlendPass 的 Bloom 纹理
|
||||
uniform sampler2DMS u_Texture;
|
||||
uniform sampler2DMS u_DepthTexture;
|
||||
uniform sampler2D u_BloomTexture;
|
||||
|
||||
uniform mat4 u_InvProjection;
|
||||
uniform mat4 u_InvView;
|
||||
|
||||
// Fog
|
||||
uniform float u_FogEnabled;
|
||||
uniform vec3 u_FogColor;
|
||||
uniform float u_FogDensity; // 雾密度,典型值 0.01~0.05
|
||||
uniform float u_FogHeight; // 雾的起始高度(世界 Y 坐标),低于此高度雾最浓
|
||||
uniform float u_FogHeightFalloff; // 高度衰减系数,值越大高度影响越剧烈(典型 0.5~2.0)
|
||||
|
||||
|
||||
|
||||
uniform bool u_EnableAutoExposure;
|
||||
uniform float u_ManualExposure;
|
||||
@ -30,36 +44,129 @@ layout(std430, binding = 2) buffer Exposure
|
||||
float u_Exposure;
|
||||
};
|
||||
|
||||
uniform bool u_EnableBloom;
|
||||
uniform int u_TextureSamples;
|
||||
|
||||
const float gamma = 2.2;
|
||||
const float pureWhite = 1.0;
|
||||
uniform bool u_EnableBloom;
|
||||
uniform float u_BloomThreshold;
|
||||
|
||||
uniform bool u_EnableSSR;
|
||||
uniform sampler2D u_SSRTexture;
|
||||
|
||||
const float uFar = 1.0;
|
||||
|
||||
vec4 SampleTexture(sampler2D tex, vec2 texCoord)
|
||||
{
|
||||
return texture(tex, texCoord);
|
||||
}
|
||||
|
||||
vec4 MultiSampleTexture(sampler2DMS tex, vec2 tc)
|
||||
{
|
||||
ivec2 texSize = textureSize(tex);
|
||||
ivec2 texCoord = ivec2(tc * texSize);
|
||||
vec4 result = vec4(0.0);
|
||||
for (int i = 0; i < u_TextureSamples; i++)
|
||||
result += texelFetch(tex, texCoord, i);
|
||||
|
||||
result /= float(u_TextureSamples);
|
||||
return result;
|
||||
}
|
||||
|
||||
float MultiSampleDepth(sampler2DMS tex, vec2 tc)
|
||||
{
|
||||
ivec2 texSize = textureSize(tex);
|
||||
ivec2 texCoord = ivec2(tc * texSize);
|
||||
float result = 0.0;
|
||||
for (int i = 0; i < u_TextureSamples; i++)
|
||||
result += texelFetch(tex, texCoord, i).r;
|
||||
result /= float(u_TextureSamples);
|
||||
return result;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// 采样 HDR 颜色(单样本)
|
||||
vec3 color = texture(u_HDRTexture, v_TexCoord).rgb;
|
||||
const float gamma = 2.2;
|
||||
const float pureWhite = 1.0;
|
||||
|
||||
// Tonemapping
|
||||
vec4 msColor = MultiSampleTexture(u_Texture, v_TexCoord);
|
||||
vec3 color = msColor.rgb;
|
||||
|
||||
// 混合 Bloom(如果启用)
|
||||
if (u_EnableBloom)
|
||||
{
|
||||
vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
|
||||
color += bloomColor; // 在 HDR 空间混合
|
||||
color += bloomColor;
|
||||
}
|
||||
|
||||
// 应用曝光
|
||||
if (u_EnableAutoExposure)
|
||||
color *= u_Exposure;
|
||||
else
|
||||
color *= u_ManualExposure;
|
||||
if (u_EnableSSR)
|
||||
{
|
||||
vec4 ssrSample = texture(u_SSRTexture, v_TexCoord);
|
||||
color += ssrSample.rgb * ssrSample.a;
|
||||
}
|
||||
|
||||
// Reinhard 色调映射
|
||||
|
||||
float exposure = 1.0f;
|
||||
if(u_EnableAutoExposure)
|
||||
exposure = u_Exposure;
|
||||
else
|
||||
exposure = u_ManualExposure;
|
||||
color *= exposure;
|
||||
|
||||
|
||||
// Reinhard tonemapping operator.
|
||||
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
|
||||
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
|
||||
float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance);
|
||||
|
||||
// 按亮度比例缩放颜色
|
||||
// Scale color by ratio of average luminances.
|
||||
vec3 mappedColor = (mappedLuminance / luminance) * color;
|
||||
|
||||
// Gamma 校正
|
||||
if (u_FogEnabled > 0.5)
|
||||
{
|
||||
// 1. 获取深度并重建视空间坐标
|
||||
float depth = MultiSampleDepth(u_DepthTexture, v_TexCoord);
|
||||
vec4 clipPos = vec4(v_TexCoord * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
vec4 viewPos4 = u_InvProjection * clipPos;
|
||||
viewPos4 /= viewPos4.w;
|
||||
vec3 viewPos = viewPos4.xyz; // 视空间坐标(相机为原点,Z 轴向内)
|
||||
|
||||
// 2. 距离雾因子(指数雾)
|
||||
float distance = length(viewPos);
|
||||
float distanceFactor = 1.0 - exp(-distance * u_FogDensity);
|
||||
// 可选:指数平方雾(更平滑)
|
||||
// float distanceFactor = 1.0 - exp(-pow(distance * u_FogDensity, 2.0));
|
||||
|
||||
// 3. 高度雾因子(基于世界 Y)
|
||||
// 将视空间坐标转换到世界空间
|
||||
vec4 worldPos4 = u_InvView* vec4(viewPos, 1.0);
|
||||
vec3 worldPos = worldPos4.xyz / worldPos4.w;
|
||||
float worldY = worldPos.y;
|
||||
|
||||
float heightFactor = 0.0;
|
||||
if (worldY < u_FogHeight)
|
||||
{
|
||||
// 低于起始高度:雾最浓,因子为 1
|
||||
heightFactor = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 高于起始高度:指数衰减,高度越高雾越淡
|
||||
float deltaY = worldY - u_FogHeight;
|
||||
heightFactor = exp(-deltaY * u_FogHeightFalloff);
|
||||
}
|
||||
// 可选:使用 clamp 限制范围
|
||||
heightFactor = clamp(heightFactor, 0.0, 1.0);
|
||||
|
||||
// 4. 综合雾因子(可相乘,也可取最大值,通常相乘)
|
||||
float fogFactor = distanceFactor * heightFactor;
|
||||
|
||||
// 5. 混合雾颜色(雾颜色直接使用 u_FogColor,已在 LDR 空间)
|
||||
mappedColor = mix(mappedColor, u_FogColor, fogFactor);
|
||||
}
|
||||
|
||||
// Gamma correction.
|
||||
o_Color = vec4(pow(mappedColor, vec3(1.0 / gamma)), 1.0);
|
||||
}
|
||||
|
||||
// Show over-exposed areas
|
||||
// if (o_Color.r > 1.0 || o_Color.g > 1.0 || o_Color.b > 1.0)
|
||||
// o_Color.rgb *= vec3(1.0, 0.25, 0.25);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[Window][DockSpace Demo]
|
||||
Pos=0,0
|
||||
Size=2560,1566
|
||||
Size=1920,1080
|
||||
Collapsed=0
|
||||
|
||||
[Window][Debug##Default]
|
||||
@ -9,32 +9,32 @@ Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Scene Hierarchy]
|
||||
Pos=2089,24
|
||||
Size=471,563
|
||||
Pos=1449,24
|
||||
Size=471,385
|
||||
Collapsed=0
|
||||
DockId=0x00000009,0
|
||||
|
||||
[Window][Properties]
|
||||
Pos=2089,589
|
||||
Size=471,977
|
||||
Pos=1449,411
|
||||
Size=471,669
|
||||
Collapsed=0
|
||||
DockId=0x0000000A,0
|
||||
|
||||
[Window][Scene Renderer]
|
||||
Pos=0,843
|
||||
Size=481,723
|
||||
Pos=0,585
|
||||
Size=481,495
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Window][Materials]
|
||||
Pos=0,24
|
||||
Size=481,817
|
||||
Size=481,559
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
|
||||
[Window][Script Engine Debug]
|
||||
Pos=2089,589
|
||||
Size=471,977
|
||||
Pos=1449,411
|
||||
Size=471,669
|
||||
Collapsed=0
|
||||
DockId=0x0000000A,2
|
||||
|
||||
@ -52,25 +52,25 @@ DockId=0x00000001,0
|
||||
|
||||
[Window][Viewport]
|
||||
Pos=483,58
|
||||
Size=1604,955
|
||||
Size=964,647
|
||||
Collapsed=0
|
||||
DockId=0x0000000B,0
|
||||
|
||||
[Window][Environment]
|
||||
Pos=2089,589
|
||||
Size=471,977
|
||||
Pos=1449,411
|
||||
Size=471,669
|
||||
Collapsed=0
|
||||
DockId=0x0000000A,1
|
||||
|
||||
[Window][Project]
|
||||
Pos=483,1015
|
||||
Size=1604,551
|
||||
Pos=483,707
|
||||
Size=964,373
|
||||
Collapsed=0
|
||||
DockId=0x0000000C,0
|
||||
|
||||
[Window][Objects]
|
||||
Pos=483,1015
|
||||
Size=1604,551
|
||||
Pos=483,707
|
||||
Size=964,373
|
||||
Collapsed=0
|
||||
DockId=0x0000000C,1
|
||||
|
||||
@ -81,12 +81,18 @@ Collapsed=0
|
||||
|
||||
[Window][##tool_bar]
|
||||
Pos=483,24
|
||||
Size=1604,32
|
||||
Size=964,32
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
|
||||
[Window][Console]
|
||||
Pos=483,707
|
||||
Size=964,373
|
||||
Collapsed=0
|
||||
DockId=0x0000000C,2
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0xC0DFADC4 Window=0xD0388BC8 Pos=0,58 Size=2560,1542 Split=X Selected=0x0C01D6D5
|
||||
DockSpace ID=0xC0DFADC4 Window=0xD0388BC8 Pos=268,189 Size=1920,1056 Split=X Selected=0x0C01D6D5
|
||||
DockNode ID=0x00000007 Parent=0xC0DFADC4 SizeRef=1557,1542 Split=X
|
||||
DockNode ID=0x00000003 Parent=0x00000007 SizeRef=481,1542 Split=Y Selected=0x5D711C2C
|
||||
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=481,817 Selected=0x5D711C2C
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.AppContext.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.AppContext.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Collections.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Collections.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Console.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Console.dll
Normal file
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Data.Common.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Data.Common.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.IO.Pipes.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.IO.Pipes.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.IO.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.IO.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Linq.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Linq.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Cache.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Cache.dll
Normal file
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Http.Rtc.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Http.Rtc.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Mail.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Mail.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Ping.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Ping.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Requests.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Requests.dll
Normal file
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Security.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Security.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Sockets.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Net.Sockets.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.ObjectModel.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.ObjectModel.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Reflection.dll
Normal file
BIN
Editor/library/mono/lib/mono/4.5/Facades/System.Reflection.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user