2 Commits

84 changed files with 3077 additions and 1441 deletions

View File

@ -24,3 +24,4 @@ endif ()
add_subdirectory(Prism) add_subdirectory(Prism)
add_subdirectory(Sandbox) add_subdirectory(Sandbox)
add_subdirectory(Editor) add_subdirectory(Editor)
add_subdirectory(PrismRuntime)

View File

@ -12,7 +12,7 @@ file(COPY ${IMGUI_INI} DESTINATION ${CMAKE_BINARY_DIR})
file(GLOB DOTNET_LIBRARY library) file(GLOB DOTNET_LIBRARY library)
file(COPY ${DOTNET_LIBRARY} DESTINATION ${CMAKE_BINARY_DIR}) 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}) add_executable(${PROJECT_NAME} ${SRC_SOURCE})

View File

@ -19,6 +19,7 @@
#include "Prism/Physics/Physics3D.h" #include "Prism/Physics/Physics3D.h"
#include "Prism/Renderer/Renderer2D.h" #include "Prism/Renderer/Renderer2D.h"
#include "Prism/Script/ScriptEngine.h" #include "Prism/Script/ScriptEngine.h"
#include "Prism/Script/ScriptWrappers.h"
namespace Prism namespace Prism
{ {
@ -51,8 +52,17 @@ namespace Prism
NewScene(); NewScene();
m_CurrentScene = m_EditorScene; m_CurrentScene = m_EditorScene;
SceneRenderer::GetOptions().ShowGrid = true;
AssetEditorPanel::RegisterDefaultEditors(); AssetEditorPanel::RegisterDefaultEditors();
FileSystem::StartWatching(); 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() void EditorLayer::OnDetach()
@ -105,7 +115,7 @@ namespace Prism
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false); Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
const auto viewProj = m_EditorCamera.GetViewProjection(); const auto viewProj = m_EditorCamera.GetViewProjection();
Renderer2D::BeginScene(viewProj, false); 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(); Renderer2D::EndScene();
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
@ -117,7 +127,7 @@ namespace Prism
Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false); Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false);
const auto viewProj = m_EditorCamera.GetViewProjection(); const auto viewProj = m_EditorCamera.GetViewProjection();
Renderer2D::BeginScene(viewProj, false); 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(); Renderer2D::EndScene();
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
@ -144,6 +154,18 @@ 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);
}
}
}
} }
void EditorLayer::OnImGuiRender() void EditorLayer::OnImGuiRender()
@ -237,7 +259,7 @@ namespace Prism
{ {
// temp // temp
if (ImGui::MenuItem("Reload C# Assembly")) 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::MenuItem("Reload assembly on play", nullptr, &m_ReloadScriptOnPlay);
ImGui::EndMenu(); ImGui::EndMenu();
@ -275,8 +297,9 @@ namespace Prism
Entity selectedEntity = m_SelectionContext.front().Entity; Entity selectedEntity = m_SelectionContext.front().Entity;
if (selectedEntity.HasComponent<MeshComponent>()) if (selectedEntity.HasComponent<MeshComponent>())
{ {
Ref<Mesh> mesh = selectedEntity.GetComponent<MeshComponent>().Mesh; auto& meshComponent = selectedEntity.GetComponent<MeshComponent>();
if (mesh)
if (Ref<Mesh> mesh = meshComponent.Mesh)
{ {
auto& materials = mesh->GetMaterials(); auto& materials = mesh->GetMaterials();
static uint32_t selectedMaterialIndex = 0; static uint32_t selectedMaterialIndex = 0;
@ -304,27 +327,13 @@ namespace Prism
} }
ImGui::EndChild(); 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(); ImGui::Separator();
if (selectedMaterialIndex < materials.size()) if (selectedMaterialIndex < materials.size())
{ {
bool shouldUpdate = false;
auto& materialInstance = materials[selectedMaterialIndex]; auto& materialInstance = materials[selectedMaterialIndex];
ImGui::Text("Shader: %s", materialInstance->GetShader()->GetName().c_str()); ImGui::Text("Shader: %s", materialInstance->GetShader()->GetName().c_str());
// Textures ------------------------------------------------------------------------------ // Textures ------------------------------------------------------------------------------
@ -339,6 +348,21 @@ namespace Prism
Ref<Texture2D> albedoMap = materialInstance->TryGetResource<Texture2D>("u_AlbedoTexture"); Ref<Texture2D> albedoMap = materialInstance->TryGetResource<Texture2D>("u_AlbedoTexture");
ImGui::Image(albedoMap ? (ImTextureRef)albedoMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64)); 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(); ImGui::PopStyleVar();
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
@ -351,28 +375,23 @@ namespace Prism
ImGui::Image((ImTextureRef)albedoMap->GetRendererID(), ImVec2(384, 384)); ImGui::Image((ImTextureRef)albedoMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip(); 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::SameLine();
ImGui::BeginGroup(); ImGui::BeginGroup();
if (ImGui::Checkbox("Use##AlbedoMap", &useAlbedoMap)) 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) materialInstance->Set<float>("u_AlbedoTexToggle", useAlbedoMap ? 1.0f : 0.0f);
m_AlbedoInput.TextureMap = Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB); shouldUpdate = true;
}*/ }
ImGui::EndGroup(); ImGui::EndGroup();
ImGui::SameLine(); ImGui::SameLine();
ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(albedoColor), ImGuiColorEditFlags_NoInputs); if (ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(albedoColor), ImGuiColorEditFlags_NoInputs))
{
meshComponent.UpdateMaterials(selectedMaterialIndex);
shouldUpdate = true;
}
} }
} }
{ {
@ -385,6 +404,21 @@ namespace Prism
Ref<Texture2D> normalMap = materialInstance->TryGetResource<Texture2D>("u_NormalTexture"); Ref<Texture2D> normalMap = materialInstance->TryGetResource<Texture2D>("u_NormalTexture");
ImGui::Image(normalMap ? (ImTextureRef)normalMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64)); 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(); ImGui::PopStyleVar();
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
@ -403,12 +437,16 @@ namespace Prism
{ {
normalMap = Texture2D::Create(filename); normalMap = Texture2D::Create(filename);
materialInstance->Set("u_NormalTexture", normalMap); materialInstance->Set("u_NormalTexture", normalMap);
shouldUpdate = true;
} }
} }
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Checkbox("Use##NormalMap", &useNormalMap)) if (ImGui::Checkbox("Use##NormalMap", &useNormalMap))
{
materialInstance->Set<float>("u_NormalTexToggle", useNormalMap ? 1.0f : 0.0f); materialInstance->Set<float>("u_NormalTexToggle", useNormalMap ? 1.0f : 0.0f);
shouldUpdate = true;
}
} }
} }
{ {
@ -422,6 +460,21 @@ namespace Prism
Ref<Texture2D> metalnessMap = materialInstance->TryGetResource<Texture2D>("u_MetalnessTexture"); Ref<Texture2D> metalnessMap = materialInstance->TryGetResource<Texture2D>("u_MetalnessTexture");
ImGui::Image(metalnessMap ? (ImTextureRef)metalnessMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64)); 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(); ImGui::PopStyleVar();
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
@ -434,20 +487,18 @@ namespace Prism
ImGui::Image((ImTextureRef)metalnessMap->GetRendererID(), ImVec2(384, 384)); ImGui::Image((ImTextureRef)metalnessMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip(); 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(); ImGui::SameLine();
if (ImGui::Checkbox("Use##MetalnessMap", &useMetalnessMap)) if (ImGui::Checkbox("Use##MetalnessMap", &useMetalnessMap))
{
materialInstance->Set<float>("u_MetalnessTexToggle", useMetalnessMap ? 1.0f : 0.0f); materialInstance->Set<float>("u_MetalnessTexToggle", useMetalnessMap ? 1.0f : 0.0f);
shouldUpdate = true;
}
ImGui::SameLine(); 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 +511,20 @@ namespace Prism
Ref<Texture2D> roughnessMap = materialInstance->TryGetResource<Texture2D>("u_RoughnessTexture"); Ref<Texture2D> roughnessMap = materialInstance->TryGetResource<Texture2D>("u_RoughnessTexture");
ImGui::Image(roughnessMap ? (ImTextureRef)roughnessMap->GetRendererID() : (ImTextureRef)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64)); 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(); ImGui::PopStyleVar();
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
@ -472,22 +537,21 @@ namespace Prism
ImGui::Image((ImTextureRef)roughnessMap->GetRendererID(), ImVec2(384, 384)); ImGui::Image((ImTextureRef)roughnessMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip(); 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(); ImGui::SameLine();
if (ImGui::Checkbox("Use##RoughnessMap", &useRoughnessMap)) if (ImGui::Checkbox("Use##RoughnessMap", &useRoughnessMap))
{
materialInstance->Set<float>("u_RoughnessTexToggle", useRoughnessMap ? 1.0f : 0.0f); materialInstance->Set<float>("u_RoughnessTexToggle", useRoughnessMap ? 1.0f : 0.0f);
shouldUpdate = true;
}
ImGui::SameLine(); 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 +569,8 @@ namespace Prism
m_ObjectsPanel->OnImGuiRender(); m_ObjectsPanel->OnImGuiRender();
m_SceneHierarchyPanel->OnImGuiRender(); m_SceneHierarchyPanel->OnImGuiRender();
m_EditorCamera.OnImGuiRender(); // m_EditorCamera.OnImGuiRender();
m_ConsolePanel->OnImGuiRender();
// Editor Panel ------------------------------------------------------------------------------ // Editor Panel ------------------------------------------------------------------------------
ImGui::Begin("Environment"); ImGui::Begin("Environment");
@ -1054,17 +1119,6 @@ namespace Prism
}); });
if (!m_SelectionContext.empty()) 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]); OnSelected(m_SelectionContext[0]);
} }
} }
@ -1164,7 +1218,7 @@ namespace Prism
UpdateWindowTitle("Untitled Scene"); UpdateWindowTitle("Untitled Scene");
m_SceneFilePath = std::string(); 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(); m_SelectionContext.clear();
} }

View File

@ -5,6 +5,7 @@
#ifndef EDITORLAYER_H #ifndef EDITORLAYER_H
#define EDITORLAYER_H #define EDITORLAYER_H
#include "Panels/ConsolePanel.h"
#include "Prism.h" #include "Prism.h"
#include "Prism/Editor/ContentBrowserPanel.h" #include "Prism/Editor/ContentBrowserPanel.h"
#include "Prism/Editor/ObjectsPanel.h" #include "Prism/Editor/ObjectsPanel.h"
@ -150,6 +151,9 @@ namespace Prism
Edit = 0, Play = 1, Pause = 2 Edit = 0, Play = 1, Pause = 2
}; };
SceneState m_SceneState = SceneState::Edit; SceneState m_SceneState = SceneState::Edit;
private:
Scope<ConsolePanel> m_ConsolePanel;
}; };
} }

View 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;
}
}

View 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

View File

@ -0,0 +1,336 @@
Scene: Scene Name
Environment:
AssetHandle: 5211537204242875091
Entities:
- 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: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
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: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
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: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
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: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
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: 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: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
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: 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: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
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: 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: 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: WalkingSpeed
Type: 1
Data: 2
- Name: RunSpeed
Type: 1
Data: 5
- Name: JumpForce
Type: 1
Data: 1
- Name: MouseSensitivity
Type: 1
Data: 10
- Name: CameraForwardOffset
Type: 1
Data: -2
- Name: CameraYOffset
Type: 1
Data: 2
MeshComponent:
AssetID: 3043502408333723884
AssetPath: assets/meshes/Default/Capsule.fbx
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: 10732070446010033158
Parent: 0
Children:
[]
TagComponent:
Tag: Cube
TransformComponent:
Position: [0, -2.6466873, 0]
Rotation: [0, 0, 0]
Scale: [100, 1, 100]
MeshComponent:
AssetID: 18328012085543462741
AssetPath: assets/meshes/Default/Cube.fbx
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: 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: 5211537204242875091
EnvironmentAssetPath: assets/env/venice_dawn_1_4k.hdr
Intensity: 1
Angle: 0
DynamicSky: false
TurbidityAzimuthInclination: [2, 0, 0]
PhysicsLayers:
[]

View File

@ -1,11 +1,50 @@
Scene: Scene Name Scene: Scene Name
Environment: Environment:
AssetHandle: 10549690553241162923 AssetHandle: 6095149963749185931
Light:
Direction: [-0.314, -0.941, -0.209]
Radiance: [0, 0, 0]
Multiplier: 1
Entities: 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 - Entity: 17803125207910630398
Parent: 0 Parent: 0
Children: Children:
@ -20,30 +59,6 @@ Entities:
Radiance: [1, 1, 1] Radiance: [1, 1, 1]
CastShadows: true CastShadows: true
SoftShadows: true SoftShadows: true
LightSize: 0.5 LightSize: 0.9
- 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
PhysicsLayers: PhysicsLayers:
[] []

View File

@ -1,12 +1,21 @@
Scene: Scene Name Scene: Scene Name
Environment: Environment:
AssetHandle: 17073147362577408906 AssetHandle: 5211537204242875091
Light:
Direction: [-0.314, -0.941, -0.209]
Radiance: [0, 0, 0]
Multiplier: 1
Entities: 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 Parent: 0
Children: Children:
[] []
@ -17,8 +26,11 @@ Entities:
Rotation: [0, 0, 0] Rotation: [0, 0, 0]
Scale: [1, 1, 1] Scale: [1, 1, 1]
SkyLightComponent: SkyLightComponent:
EnvironmentMap: 17073147362577408906 EnvironmentMap: 5211537204242875091
EnvironmentAssetPath: assets/env/venice_dawn_1_4k.hdr
Intensity: 1 Intensity: 1
Angle: 0 Angle: 0
DynamicSky: false
TurbidityAzimuthInclination: [2, 0, 0]
PhysicsLayers: PhysicsLayers:
[] []

View File

@ -24,16 +24,16 @@ uniform sampler2D u_Texture;
uniform bool u_Horizontal; // 未使用,可保留或移除 uniform bool u_Horizontal; // 未使用,可保留或移除
uniform bool u_FirstPass; // 是否进行阈值处理 uniform bool u_FirstPass; // 是否进行阈值处理
uniform float u_Threshold; // 亮度阈值 uniform float u_Threshold; // 亮度阈值
uniform int u_Quality;
uniform float u_Directions; // 模糊方向数
uniform float u_Size; // 模糊半径
void main() void main()
{ {
float Pi = 6.28318530718; // 2*PI 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; vec3 centerColor = texture(u_Texture, v_TexCoord).rgb;
@ -50,9 +50,9 @@ void main()
float totalSamples = 1.0; // 有效采样计数(中心像素已计入) 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; vec2 offset = vec2(cos(d), sin(d)) * Radius * i;
vec3 sampleColor = texture(u_Texture, v_TexCoord + offset).rgb; vec3 sampleColor = texture(u_Texture, v_TexCoord + offset).rgb;

View File

@ -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);
}

View File

@ -161,13 +161,6 @@ uniform float u_ShadowSoftness;
uniform float u_ShadowIntensity; uniform float u_ShadowIntensity;
uniform int u_ShadowEnabled; uniform int u_ShadowEnabled;
// Emissive
uniform sampler2D u_EmissiveTexture;
uniform float u_EmissiveTexToggle;
uniform vec3 u_EmissiveColor;
uniform float u_EmissiveIntensity;
struct PBRParameters struct PBRParameters
{ {
vec3 Albedo; vec3 Albedo;
@ -432,16 +425,7 @@ float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
void main() void main()
{ {
float alpha = 1.0; m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
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.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness; 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 = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
m_Params.Roughness = max(m_Params.Roughness, 0.05); m_Params.Roughness = max(m_Params.Roughness, 0.05);
@ -479,16 +463,7 @@ void main()
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution; vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
vec3 emissive = u_EmissiveColor; color = vec4(lightContribution + iblContribution, 1.0);
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;
// Bloom // Bloom
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722)); float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));

View File

@ -55,12 +55,6 @@ void main()
#type fragment #type fragment
#version 430 core #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 PI = 3.141592;
const float Epsilon = 0.00001; const float Epsilon = 0.00001;
@ -106,8 +100,8 @@ in VertexOutput
vec4 FragPosLightSpace; vec4 FragPosLightSpace;
} vs_Input; } vs_Input;
layout(location = 0) out vec4 color;
uniform bool u_GBufferMode; layout(location = 1) out vec4 o_BloomColor;
uniform DirectionalLight u_DirectionalLights; uniform DirectionalLight u_DirectionalLights;
@ -155,12 +149,6 @@ uniform float u_ShadowSoftness;
uniform float u_ShadowIntensity; uniform float u_ShadowIntensity;
uniform int u_ShadowEnabled; uniform int u_ShadowEnabled;
// Emissive
uniform sampler2D u_EmissiveTexture;
uniform float u_EmissiveTexToggle;
uniform vec3 u_EmissiveColor;
uniform float u_EmissiveIntensity;
struct PBRParameters struct PBRParameters
{ {
vec3 Albedo; vec3 Albedo;
@ -423,44 +411,19 @@ float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
void main() void main()
{ {
// === 1. 采样基础属性(所有模式都需要) === m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
vec4 albedoWithAlpha = texture(u_AlbedoTexture, vs_Input.TexCoord); m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
vec3 albedo = u_AlbedoTexToggle > 0.5 ? albedoWithAlpha.rgb : u_AlbedoColor; m_Params.Roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
float alpha = u_AlbedoTexToggle > 0.5 ? albedoWithAlpha.a : 1.0; m_Params.Roughness = max(m_Params.Roughness, 0.05);
float metallic = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness; // normal
float roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness; m_Params.Normal = normalize(vs_Input.Normal);
roughness = max(roughness, 0.05);
// === 2. 法线计算(世界空间) ===
vec3 normal = normalize(vs_Input.Normal);
if (u_NormalTexToggle > 0.5) if (u_NormalTexToggle > 0.5)
{ {
vec3 tangentNormal = texture(u_NormalTexture, vs_Input.TexCoord).rgb * 2.0 - 1.0; m_Params.Normal = normalize(2.0 * texture(u_NormalTexture, vs_Input.TexCoord).rgb - 1.0);
normal = normalize(vs_Input.WorldNormals * tangentNormal); 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.View = normalize(u_CameraPosition - vs_Input.WorldPosition);
m_Params.NdotV = max(dot(m_Params.Normal, m_Params.View), 0.0); m_Params.NdotV = max(dot(m_Params.Normal, m_Params.View), 0.0);
@ -486,12 +449,9 @@ void main()
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution; vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
vec3 finalRGB = lightContribution + iblContribution + emissive; color = vec4(lightContribution + iblContribution, 1.0);
vec4 finalColor = vec4(finalRGB, alpha);
outColor = finalColor;
// Bloom // Bloom
float brightness = dot(finalColor.rgb, vec3(0.2126, 0.7152, 0.0722)); float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
outBloomColor = brightness > u_BloomThreshold ? finalColor : vec4(0.0, 0.0, 0.0, 1.0); o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
} }

View File

@ -17,11 +17,13 @@ void main()
#version 430 #version 430
layout(location = 0) out vec4 o_Color; layout(location = 0) out vec4 o_Color;
layout(location = 1) out vec4 o_BloomTexture;
in vec2 v_TexCoord; in vec2 v_TexCoord;
uniform sampler2D u_HDRTexture; // 来自 LightingPass 的 HDR 颜色 uniform sampler2DMS u_Texture;
uniform sampler2D u_BloomTexture; // 来自 BloomBlendPass 的 Bloom 纹理 uniform sampler2D u_BloomTexture;
uniform bool u_EnableAutoExposure; uniform bool u_EnableAutoExposure;
uniform float u_ManualExposure; uniform float u_ManualExposure;
@ -30,36 +32,73 @@ layout(std430, binding = 2) buffer Exposure
float u_Exposure; float u_Exposure;
}; };
uniform bool u_EnableBloom; uniform int u_TextureSamples;
const float gamma = 2.2; uniform bool u_EnableBloom;
const float pureWhite = 1.0; uniform float u_BloomThreshold;
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() void main()
{ {
// 采样 HDR 颜色(单样本) const float gamma = 2.2;
vec3 color = texture(u_HDRTexture, v_TexCoord).rgb; const float pureWhite = 1.0;
// Tonemapping
vec4 msColor = MultiSampleTexture(u_Texture, v_TexCoord);
vec3 color = msColor.rgb;
// 混合 Bloom如果启用
if (u_EnableBloom) if (u_EnableBloom)
{ {
vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb; vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
color += bloomColor; // 在 HDR 空间混合 color += bloomColor;
} }
// 应用曝光 if(u_EnableAutoExposure)
if (u_EnableAutoExposure) color *= u_Exposure;
color *= u_Exposure;
else else
color *= u_ManualExposure; color *= u_ManualExposure;
// Reinhard 色调映射 // Reinhard tonemapping operator.
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722)); float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance); float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance);
// 按亮度比例缩放颜色 // Scale color by ratio of average luminances.
vec3 mappedColor = (mappedLuminance / luminance) * color; vec3 mappedColor = (mappedLuminance / luminance) * color;
// Gamma 校正 // Gamma correction.
o_Color = vec4(pow(mappedColor, vec3(1.0 / gamma)), 1.0); 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);
} }

View File

@ -1,6 +1,6 @@
[Window][DockSpace Demo] [Window][DockSpace Demo]
Pos=0,0 Pos=0,0
Size=2560,1566 Size=1920,1080
Collapsed=0 Collapsed=0
[Window][Debug##Default] [Window][Debug##Default]
@ -9,32 +9,32 @@ Size=400,400
Collapsed=0 Collapsed=0
[Window][Scene Hierarchy] [Window][Scene Hierarchy]
Pos=2089,24 Pos=1449,24
Size=471,563 Size=471,385
Collapsed=0 Collapsed=0
DockId=0x00000009,0 DockId=0x00000009,0
[Window][Properties] [Window][Properties]
Pos=2089,589 Pos=1449,411
Size=471,977 Size=471,669
Collapsed=0 Collapsed=0
DockId=0x0000000A,0 DockId=0x0000000A,0
[Window][Scene Renderer] [Window][Scene Renderer]
Pos=0,843 Pos=0,585
Size=481,723 Size=481,495
Collapsed=0 Collapsed=0
DockId=0x00000006,0 DockId=0x00000006,0
[Window][Materials] [Window][Materials]
Pos=0,24 Pos=0,24
Size=481,817 Size=481,559
Collapsed=0 Collapsed=0
DockId=0x00000005,0 DockId=0x00000005,0
[Window][Script Engine Debug] [Window][Script Engine Debug]
Pos=2089,589 Pos=1449,411
Size=471,977 Size=471,669
Collapsed=0 Collapsed=0
DockId=0x0000000A,2 DockId=0x0000000A,2
@ -52,25 +52,25 @@ DockId=0x00000001,0
[Window][Viewport] [Window][Viewport]
Pos=483,58 Pos=483,58
Size=1604,955 Size=964,647
Collapsed=0 Collapsed=0
DockId=0x0000000B,0 DockId=0x0000000B,0
[Window][Environment] [Window][Environment]
Pos=2089,589 Pos=1449,411
Size=471,977 Size=471,669
Collapsed=0 Collapsed=0
DockId=0x0000000A,1 DockId=0x0000000A,1
[Window][Project] [Window][Project]
Pos=483,1015 Pos=483,707
Size=1604,551 Size=964,373
Collapsed=0 Collapsed=0
DockId=0x0000000C,0 DockId=0x0000000C,0
[Window][Objects] [Window][Objects]
Pos=483,1015 Pos=483,707
Size=1604,551 Size=964,373
Collapsed=0 Collapsed=0
DockId=0x0000000C,1 DockId=0x0000000C,1
@ -81,12 +81,18 @@ Collapsed=0
[Window][##tool_bar] [Window][##tool_bar]
Pos=483,24 Pos=483,24
Size=1604,32 Size=964,32
Collapsed=0 Collapsed=0
DockId=0x00000001,0 DockId=0x00000001,0
[Window][Console]
Pos=483,707
Size=964,373
Collapsed=0
DockId=0x0000000C,2
[Docking][Data] [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=0x00000007 Parent=0xC0DFADC4 SizeRef=1557,1542 Split=X
DockNode ID=0x00000003 Parent=0x00000007 SizeRef=481,1542 Split=Y Selected=0x5D711C2C DockNode ID=0x00000003 Parent=0x00000007 SizeRef=481,1542 Split=Y Selected=0x5D711C2C
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=481,817 Selected=0x5D711C2C DockNode ID=0x00000005 Parent=0x00000003 SizeRef=481,817 Selected=0x5D711C2C

View File

@ -4,6 +4,7 @@
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,3 +1,4 @@
using System.Runtime.InteropServices;
using Prism; using Prism;
namespace FPSExample namespace FPSExample
@ -8,6 +9,8 @@ namespace FPSExample
public float RunSpeed = 20.0f; public float RunSpeed = 20.0f;
public float JumpForce = 50.0f; public float JumpForce = 50.0f;
public float m_Radius = 0.5f;
public float TorqueStrength = 10.0f;
[NonSerialized] [NonSerialized]
public float MouseSensitivity = 10.0f; public float MouseSensitivity = 10.0f;
@ -46,6 +49,9 @@ namespace FPSExample
m_LastMousePosition = Input.GetMousePosition(); m_LastMousePosition = Input.GetMousePosition();
Input.SetCursorMode(Input.CursorMode.Locked); Input.SetCursorMode(Input.CursorMode.Locked);
int size = Marshal.SizeOf<Transform>();
Console.WriteLine($"C# size of Transform: {size}");
} }
void OnUpdate(float ts) void OnUpdate(float ts)
@ -65,14 +71,19 @@ namespace FPSExample
UpdateCameraTransform(); UpdateCameraTransform();
} }
void OnPhysicsUpdate(float fixedTimeStep)
{
UpdateMovement();
}
private void UpdateRotation(float ts) private void UpdateRotation(float ts)
{ {
Vec2 currentMousePosition = Input.GetMousePosition(); Vec2 currentMousePosition = Input.GetMousePosition();
Vec2 delta = m_LastMousePosition - currentMousePosition; Vec2 delta = m_LastMousePosition - currentMousePosition;
float m_CurrentYMovement = delta.X * MouseSensitivity * ts; m_CurrentYMovement = delta.X * MouseSensitivity * ts;
float xRotation = delta.Y * MouseSensitivity * ts; float xRotation = delta.Y * MouseSensitivity * ts;
m_RigidBody.Rotate(new Vec3(0.0f, m_CurrentYMovement, 0.0f)); // m_RigidBody.Rotate(new Vec3(0.0f, m_CurrentYMovement, 0.0f));
if (delta.X != 0 || delta.Y != 0) if (delta.X != 0 || delta.Y != 0)
{ {
@ -86,17 +97,25 @@ namespace FPSExample
private void UpdateMovementInput() private void UpdateMovementInput()
{ {
if (Input.IsKeyPressed(KeyCode.W)) if (Input.IsKeyPressed(KeyCode.W)){
m_MovementDirection.Y += 1.0f;
else if (Input.IsKeyPressed(KeyCode.S))
m_MovementDirection.Y -= 1.0f; m_MovementDirection.Y -= 1.0f;
Debug.Log("KeyPressed: W");
}
else if (Input.IsKeyPressed(KeyCode.S)){
m_MovementDirection.Y += 1.0f;
Debug.Log("KeyPressed: S");
}
else else
m_MovementDirection.Y = 0.0f; m_MovementDirection.Y = 0.0f;
if(Input.IsKeyPressed(KeyCode.A)) if(Input.IsKeyPressed(KeyCode.A)){
m_MovementDirection.X -= 1.0f;
else if (Input.IsKeyPressed(KeyCode.D))
m_MovementDirection.X += 1.0f; m_MovementDirection.X += 1.0f;
Debug.Log("KeyPressed: A");
}
else if (Input.IsKeyPressed(KeyCode.D)){
m_MovementDirection.X -= 1.0f;
Debug.Log("KeyPressed: D");
}
else else
m_MovementDirection.X = 0.0f; m_MovementDirection.X = 0.0f;
@ -132,26 +151,64 @@ namespace FPSExample
} }
void OnPhysicsUpdate(float fixedTimeStep)
{
UpdateMovement();
}
private void UpdateMovement() private void UpdateMovement()
{ {
m_RigidBody.Rotate(new Vec3(0.0f, m_CurrentYMovement, 0.0f)); // 2. 计算期望的移动方向(世界坐标系)
Vec3 desiredDirection = Vec3.Zero;
Vec3 movement = m_CameraTransform.Transform.Right * m_MovementDirection.X + m_CameraTransform.Transform.Forward * m_MovementDirection.Y;
if (m_MovementDirection.LengthSquared() != 0.0f) if (m_MovementDirection.LengthSquared() != 0.0f)
{ {
Vec3 right = m_CameraTransform.Transform.Right;
Vec3 forward = m_CameraTransform.Transform.Forward;
right.Y = 0; forward.Y = 0;
right.Normalize(); forward.Normalize();
desiredDirection = right * m_MovementDirection.X + forward * m_MovementDirection.Y;
desiredDirection.Normalize();
/*
Vec3 movement = right * m_MovementDirection.X + forward * m_MovementDirection.Y;
movement.Normalize(); movement.Normalize();
Vec3 velocity = movement * m_CurrentSpeed; Vec3 velocity = movement * m_CurrentSpeed;
velocity.Y = m_RigidBody.GetLinearVelocity().Y; velocity.Y = m_RigidBody.GetLinearVelocity().Y;
m_RigidBody.SetLinearVelocity(velocity); m_RigidBody.SetLinearVelocity(velocity);
*/
} }
Vec3 targetAngularVelocity = Vec3.Zero;
if (desiredDirection.LengthSquared() > 0.01f)
{
Vec3 up = Vec3.Up;
Vec3 rotationAxis = Vec3.Cross(desiredDirection, up).Normalized();
float angularSpeed = 2 * (m_CurrentSpeed / m_Radius);
targetAngularVelocity = rotationAxis * angularSpeed;
Vec3 currentAngular = m_RigidBody.GetAngularVelocity();
Vec3 angularDiff = targetAngularVelocity - currentAngular;
float inertia = 0.4f * m_RigidBody.Mass * m_Radius * m_Radius;
Vec3 torque = angularDiff * inertia * TorqueStrength;
m_RigidBody.AddTorque(torque, RigidBodyComponent.ForceMode.Force);
}
/*
// 3. 获取当前角速度,计算需要调整的差值
Vec3 currentAngular = m_RigidBody.GetAngularVelocity();
Vec3 angularDiff = targetAngularVelocity - currentAngular;
// 4. 施加扭矩:扭矩 = 转动惯量 * 角加速度
// 球体的转动惯量 I = (2/5) * m * r^2 (实心球)
float inertia = TorqueStrength * m_RigidBody.Mass * m_Radius * m_Radius;
// 设定一个系数控制响应速度(可调)
float torqueStrength = 5.0f;
Vec3 torque = angularDiff * inertia * torqueStrength;
m_RigidBody.AddTorque(-torque, RigidBodyComponent.ForceMode.Force);
*/
if (m_ShouldJump && m_Colliding) if (m_ShouldJump && m_Colliding)
{ {
Debug.Log("Jump");
m_RigidBody.AddForce(Vec3.Up * JumpForce, RigidBodyComponent.ForceMode.Impulse); m_RigidBody.AddForce(Vec3.Up * JumpForce, RigidBodyComponent.ForceMode.Impulse);
m_ShouldJump = false; m_ShouldJump = false;
} }
@ -159,7 +216,7 @@ namespace FPSExample
private void UpdateCameraTransform(){ private void UpdateCameraTransform(){
Vec3 position = m_Transform.Translation + m_CameraTransform.Transform.Forward * CameraForwardOffset; Vec3 position = m_Transform.Translation + m_CameraTransform.Transform.Forward * CameraForwardOffset;
position.Y += m_Transform.Translation.Y + CameraYOffset; position.Y += CameraYOffset;
m_CameraTransform.Translation = position; m_CameraTransform.Translation = position;
} }
} }

View File

@ -5,6 +5,7 @@
<RootNamespace>Prism_ScriptCore</RootNamespace> <RootNamespace>Prism_ScriptCore</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,15 @@
using System.Runtime.CompilerServices;
namespace Prism
{
public class Debug
{
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void Log_Native(string message);
public static void Log(string message)
{
Log_Native(message);
}
}
}

View File

@ -9,8 +9,8 @@ namespace Prism
public Vec3 Rotation; public Vec3 Rotation;
public Vec3 Scale; public Vec3 Scale;
public Vec3 Up { get; } public Vec3 Up;
public Vec3 Right { get; } public Vec3 Right;
public Vec3 Forward { get; } public Vec3 Forward;
} }
} }

View File

@ -53,6 +53,15 @@ namespace Prism
Z = vec.Z; Z = vec.Z;
} }
public static Vec3 Cross(Vec3 a, Vec3 b)
{
return new Vec3(
a.Y * b.Z - a.Z * b.Y,
a.Z * b.X - a.X * b.Z,
a.X * b.Y - a.Y * b.X
);
}
public void Clamp(Vec3 min, Vec3 max) public void Clamp(Vec3 min, Vec3 max)
{ {
X = Mathf.Clamp(X, min.X, max.X); X = Mathf.Clamp(X, min.X, max.X);
@ -60,6 +69,7 @@ namespace Prism
Z = Mathf.Clamp(Z, min.Z, max.Z); Z = Mathf.Clamp(Z, min.Z, max.Z);
} }
public float LengthSquared() public float LengthSquared()
{ {
return X * X + Y * Y + Z * Z; return X * X + Y * Y + Z * Z;

View File

@ -197,7 +197,45 @@ set_target_properties(${SHARED_LIBRARY} PROPERTIES
) )
# static runtime library
set(RUNTIME_LIBRARY ${PROJECT_NAME}-Runtime)
add_library(${RUNTIME_LIBRARY} STATIC ${SRC_SOURCE})
target_compile_definitions(${RUNTIME_LIBRARY} PRIVATE
PRISM_RUNTIME
INTERFACE
PRISM_STATIC
)
target_include_directories(${RUNTIME_LIBRARY} PUBLIC
${TARGET_INCLUDE_DIR}
)
target_link_directories(${RUNTIME_LIBRARY} INTERFACE
${PHYSX_LIB_DIR}
)
target_link_libraries(${RUNTIME_LIBRARY}
PRIVATE
${LINK_LIBRARIES_PRIVATE}
PUBLIC
${LINK_LIBRARIES_PUBLIC}
)
target_precompile_headers(${RUNTIME_LIBRARY} PRIVATE
src/pmpch.h
)
set_target_properties(${RUNTIME_LIBRARY} PROPERTIES
OUTPUT_NAME ${PROJECT_NAME}
ARCHIVE_OUTPUT_NAME ${PROJECT_NAME}rd
)
# alias # alias
add_library(Prism::static ALIAS Prism-static) add_library(Prism::static ALIAS Prism-static)
add_library(Prism::shared ALIAS Prism-shared) add_library(Prism::shared ALIAS Prism-shared)
add_library(Prism ALIAS Prism-shared) add_library(Prism ALIAS Prism-shared)
add_library(Prism::Runtime ALIAS Prism-Runtime)

View File

@ -0,0 +1,25 @@
//
// Created by Atdunbg on 2026/3/26.
//
#include "Asset.h"
#include "Prism/Renderer/Texture.h"
namespace Prism
{
PhysicsMaterialAsset::PhysicsMaterialAsset(): StaticFriction(0), DynamicFriction(0), Bounciness(0)
{
Type = AssetType::PhysicsMaterial;
}
PhysicsMaterialAsset::PhysicsMaterialAsset(const float staticFriction, const float dynamicFriction,
const float bounciness): StaticFriction(staticFriction), DynamicFriction(dynamicFriction), Bounciness(bounciness)
{
Type = AssetType::PhysicsMaterial;
}
PBRMaterialAsset::PBRMaterialAsset()
{
Type = AssetType::Material;
}
}

View File

@ -5,14 +5,20 @@
#ifndef PRISM_ASSET_H #ifndef PRISM_ASSET_H
#define PRISM_ASSET_H #define PRISM_ASSET_H
#include <glm/glm.hpp>
#include "Prism/Core/UUID.h" #include "Prism/Core/UUID.h"
#include "Prism/Core/Ref.h" #include "Prism/Core/Ref.h"
namespace Prism namespace Prism
{ {
class Texture2D;
class Shader;
class MaterialInstance;
enum class AssetType enum class AssetType
{ {
Scene = 0, Mesh, Texture, EnvMap, Audio, Script, PhysicsMaterial, Directory, Other, None Scene = 0, Mesh, Texture, EnvMap, Audio, Script, Material, PhysicsMaterial, Directory, Other, None
}; };
using AssetHandle = UUID; using AssetHandle = UUID;
@ -35,20 +41,17 @@ namespace Prism
} }
}; };
class PRISM_API PhysicsMaterial : public Asset class PRISM_API PhysicsMaterialAsset : public Asset
{ {
public: public:
float StaticFriction; float StaticFriction;
float DynamicFriction; float DynamicFriction;
float Bounciness; float Bounciness;
PhysicsMaterial() = default; PhysicsMaterialAsset();
PhysicsMaterialAsset(const float staticFriction, const float dynamicFriction, const float bounciness);
PhysicsMaterial(const float staticFriction, const float dynamicFriction, const float bounciness)
: StaticFriction(staticFriction), DynamicFriction(dynamicFriction), Bounciness(bounciness)
{
Type = AssetType::PhysicsMaterial;
}
}; };
// Treating directories as assets simplifies the asset manager window rendering by a lot // Treating directories as assets simplifies the asset manager window rendering by a lot
@ -63,6 +66,34 @@ namespace Prism
} }
}; };
class PBRMaterialAsset : public Asset
{
public:
PBRMaterialAsset();
virtual ~PBRMaterialAsset() = default;
// Albedo
glm::vec3 AlbedoColor = glm::vec3(1.0f);
float AlbedoTexToggle = 0.0f;
Ref<Texture2D> AlbedoTexture;
// Normal
float NormalTexToggle = 0.0f;
Ref<Texture2D> NormalTexture;
// Metalness
float Metalness = 0.8f;
float MetalnessTexToggle = 0.0f;
Ref<Texture2D> MetalnessTexture;
// Roughness
float Roughness = 0.1f;
float RoughnessTexToggle = 0.0f;
Ref<Texture2D> RoughnessTexture;
bool IsDirty = true;
};
} }
#endif //PRISM_ASSET_H #endif //PRISM_ASSET_H

View File

@ -12,6 +12,7 @@
#include "Prism/Renderer/SceneRenderer.h" #include "Prism/Renderer/SceneRenderer.h"
#include "yaml-cpp/yaml.h" #include "yaml-cpp/yaml.h"
#include "Prism/Utilities/SerializeUtils.h"
namespace Prism namespace Prism
{ {
@ -40,15 +41,114 @@ namespace Prism
{ {
case Prism::AssetType::PhysicsMaterial: case Prism::AssetType::PhysicsMaterial:
{ {
Ref<PhysicsMaterial> material = Ref<PhysicsMaterial>(asset); Ref<PhysicsMaterialAsset> physicsMaterial = Ref<PhysicsMaterialAsset>(asset);
out << YAML::Key << "StaticFriction" << material->StaticFriction; out << YAML::Key << "StaticFriction" << physicsMaterial->StaticFriction;
out << YAML::Key << "DynamicFriction" << material->DynamicFriction; out << YAML::Key << "DynamicFriction" << physicsMaterial->DynamicFriction;
out << YAML::Key << "Bounciness" << material->Bounciness; out << YAML::Key << "Bounciness" << physicsMaterial->Bounciness;
break;
}
case AssetType::Material:
{
const auto& material = Ref<PBRMaterialAsset>(asset);
// Albedo
out << YAML::Key << "Albedo";
out << YAML::BeginMap;
{
out << YAML::Key << "Color" << YAML::Value << material->AlbedoColor;
out << YAML::Key << "TexToggle" << YAML::Value << material->AlbedoTexToggle;
out << YAML::Key << "Texture";
out << YAML::BeginMap;
if (material->AlbedoTexture)
{
out << YAML::Key << "AssetHandle" << YAML::Value << material->AlbedoTexture->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << material->AlbedoTexture->FilePath;
}
else
{
out << YAML::Key << "AssetHandle" << YAML::Value << 0;
out << YAML::Key << "AssetPath" << YAML::Value << "";
}
out << YAML::EndMap;
}
out << YAML::EndMap;
// Normal
out << YAML::Key << "Normal";
out << YAML::BeginMap;
{
out << YAML::Key << "TexToggle" << YAML::Value << material->NormalTexToggle;
out << YAML::Key << "Texture";
out << YAML::BeginMap;
if (material->NormalTexture)
{
out << YAML::Key << "AssetHandle" << YAML::Value << material->NormalTexture->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << material->NormalTexture->FilePath;
}
else
{
out << YAML::Key << "AssetHandle" << YAML::Value << 0;
out << YAML::Key << "AssetPath" << YAML::Value << "";
}
out << YAML::EndMap;
}
out << YAML::EndMap;
// Metalness
out << YAML::Key << "Metalness";
out << YAML::BeginMap;
{
out << YAML::Key << "Value" << YAML::Value << material->Metalness; // 金属度数值
out << YAML::Key << "TexToggle" << YAML::Value << material->MetalnessTexToggle;
out << YAML::Key << "Texture";
out << YAML::BeginMap;
if (material->MetalnessTexture)
{
out << YAML::Key << "AssetHandle" << YAML::Value << material->MetalnessTexture->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << material->MetalnessTexture->FilePath;
}
else
{
out << YAML::Key << "AssetHandle" << YAML::Value << 0;
out << YAML::Key << "AssetPath" << YAML::Value << "";
}
out << YAML::EndMap;
}
out << YAML::EndMap;
// Roughness
out << YAML::Key << "Roughness";
out << YAML::BeginMap;
{
out << YAML::Key << "Value" << YAML::Value << material->Roughness; // 粗糙度数值
out << YAML::Key << "TexToggle" << YAML::Value << material->RoughnessTexToggle;
out << YAML::Key << "Texture";
out << YAML::BeginMap;
if (material->RoughnessTexture)
{
out << YAML::Key << "AssetHandle" << YAML::Value << material->RoughnessTexture->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << material->RoughnessTexture->FilePath;
}
else
{
out << YAML::Key << "AssetHandle" << YAML::Value << 0;
out << YAML::Key << "AssetPath" << YAML::Value << "";
}
out << YAML::EndMap;
}
out << YAML::EndMap;
break; break;
} }
} }
out << YAML::EndMap; out << YAML::EndMap;
PM_CORE_INFO("Save Asset change...");
std::ofstream fout(asset->FilePath); std::ofstream fout(asset->FilePath);
fout << out.c_str(); fout << out.c_str();
} }
@ -61,13 +161,125 @@ namespace Prism
YAML::Node data = YAML::Load(strStream.str()); YAML::Node data = YAML::Load(strStream.str());
if (asset->Type == AssetType::PhysicsMaterial) switch (asset->Type)
{ {
float staticFriction = data["StaticFriction"].as<float>(); case AssetType::PhysicsMaterial:
float dynamicFriction = data["DynamicFriction"].as<float>(); {
float bounciness = data["Bounciness"].as<float>(); float staticFriction = data["StaticFriction"].as<float>();
float dynamicFriction = data["DynamicFriction"].as<float>();
float bounciness = data["Bounciness"].as<float>();
return Ref<PhysicsMaterial>::Create(staticFriction, dynamicFriction, bounciness); return Ref<PhysicsMaterialAsset>::Create(staticFriction, dynamicFriction, bounciness);
}
case AssetType::Material:
{
Ref<PBRMaterialAsset> material = Ref<PBRMaterialAsset>::Create();
// ==================== Albedo ====================
if (data["Albedo"])
{
auto albedoNode = data["Albedo"];
material->AlbedoColor = albedoNode["Color"].as<glm::vec3>();
material->AlbedoTexToggle = albedoNode["TexToggle"].as<float>();
if (albedoNode["Texture"])
{
auto texNode = albedoNode["Texture"];
UUID texHandle = 0;
std::string texPath;
if (texNode["AssetHandle"])
texHandle = texNode["AssetHandle"].as<uint64_t>();
if (texNode["AssetPath"])
texPath = texNode["AssetPath"].as<std::string>();
if (texHandle != 0 && AssetsManager::IsAssetHandleValid(texHandle))
material->AlbedoTexture = AssetsManager::GetAsset<Texture2D>(texHandle);
else if (!texPath.empty())
material->AlbedoTexture = Texture2D::Create(texPath);
else
material->AlbedoTexture = nullptr;
}
}
// ==================== Normal ====================
if (data["Normal"])
{
auto normalNode = data["Normal"];
material->NormalTexToggle = normalNode["TexToggle"].as<float>();
if (normalNode["Texture"])
{
auto texNode = normalNode["Texture"];
UUID texHandle = 0;
std::string texPath;
if (texNode["AssetHandle"])
texHandle = texNode["AssetHandle"].as<uint64_t>();
if (texNode["AssetPath"])
texPath = texNode["AssetPath"].as<std::string>();
if (texHandle != 0 && AssetsManager::IsAssetHandleValid(texHandle))
material->NormalTexture = AssetsManager::GetAsset<Texture2D>(texHandle);
else if (!texPath.empty())
material->NormalTexture = Texture2D::Create(texPath);
else
material->NormalTexture = nullptr;
}
}
// ==================== Metalness ====================
if (data["Metalness"])
{
auto metalNode = data["Metalness"];
material->Metalness = metalNode["Value"].as<float>();
material->MetalnessTexToggle = metalNode["TexToggle"].as<float>();
if (metalNode["Texture"])
{
auto texNode = metalNode["Texture"];
UUID texHandle = 0;
std::string texPath;
if (texNode["AssetHandle"])
texHandle = texNode["AssetHandle"].as<uint64_t>();
if (texNode["AssetPath"])
texPath = texNode["AssetPath"].as<std::string>();
if (texHandle != 0 && AssetsManager::IsAssetHandleValid(texHandle))
material->MetalnessTexture = AssetsManager::GetAsset<Texture2D>(texHandle);
else if (!texPath.empty())
material->MetalnessTexture = Texture2D::Create(texPath);
else
material->MetalnessTexture = nullptr;
}
}
// ==================== Roughness ====================
if (data["Roughness"])
{
auto roughNode = data["Roughness"];
material->Roughness = roughNode["Value"].as<float>();
material->RoughnessTexToggle = roughNode["TexToggle"].as<float>();
if (roughNode["Texture"])
{
auto texNode = roughNode["Texture"];
UUID texHandle = 0;
std::string texPath;
if (texNode["AssetHandle"])
texHandle = texNode["AssetHandle"].as<uint64_t>();
if (texNode["AssetPath"])
texPath = texNode["AssetPath"].as<std::string>();
if (texHandle != 0 && AssetsManager::IsAssetHandleValid(texHandle))
material->RoughnessTexture = AssetsManager::GetAsset<Texture2D>(texHandle);
else if (!texPath.empty())
material->RoughnessTexture = Texture2D::Create(texPath);
else
material->RoughnessTexture = nullptr;
}
}
return material;
}
} }
return nullptr; return nullptr;
@ -106,8 +318,10 @@ namespace Prism
asset->ParentDirectory = parentHandle; asset->ParentDirectory = parentHandle;
asset->IsDataLoaded = false; asset->IsDataLoaded = false;
#ifndef PRISM_RUNTIME
if (!hasMeta) if (!hasMeta)
CreateMetaFile(asset); CreateMetaFile(asset);
#endif
return asset; return asset;
} }
@ -191,7 +405,9 @@ namespace Prism
if (asset->FileName == "assets" && asset->Handle == 0) if (asset->FileName == "assets" && asset->Handle == 0)
{ {
asset->Handle = AssetHandle(); asset->Handle = AssetHandle();
#ifndef PRISM_RUNTIME
CreateMetaFile(asset); CreateMetaFile(asset);
#endif
} }
} }
@ -208,4 +424,17 @@ namespace Prism
std::ofstream fout(asset->FilePath + ".meta"); std::ofstream fout(asset->FilePath + ".meta");
fout << out.c_str(); fout << out.c_str();
} }
void AssetSerializer::UpdateMetaFile(const Ref<Asset>& asset)
{
YAML::Emitter out;
out << YAML::BeginMap;
out << YAML::Key << "Asset" << YAML::Value << asset->Handle;
out << YAML::Key << "FilePath" << YAML::Value << asset->FilePath;
out << YAML::Key << "Type" << YAML::Value << (int)asset->Type;
out << YAML::EndMap;
std::ofstream fout(asset->FilePath + ".meta");
fout << out.c_str();
}
} }

View File

@ -28,6 +28,7 @@ namespace Prism
static Ref<Asset> DeserializeYAML(const Ref<Asset>& asset); static Ref<Asset> DeserializeYAML(const Ref<Asset>& asset);
static void LoadMetaData(Ref<Asset>& asset); static void LoadMetaData(Ref<Asset>& asset);
static void CreateMetaFile(const Ref<Asset>& asset); static void CreateMetaFile(const Ref<Asset>& asset);
static void UpdateMetaFile(const Ref<Asset>& asset);
private: private:
friend class AssetsManager; friend class AssetsManager;

View File

@ -13,6 +13,7 @@
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include "AssetSerializer.h" #include "AssetSerializer.h"
#include "Prism/Core/Application.h"
#include "Prism/Renderer/SceneEnvironment.h" #include "Prism/Renderer/SceneEnvironment.h"
#include "Prism/Utilities/StringUtils.h" #include "Prism/Utilities/StringUtils.h"
@ -26,9 +27,13 @@ namespace Prism
s_Types["dae"] = AssetType::Mesh; s_Types["dae"] = AssetType::Mesh;
s_Types["obj"] = AssetType::Mesh; s_Types["obj"] = AssetType::Mesh;
s_Types["png"] = AssetType::Texture; s_Types["png"] = AssetType::Texture;
s_Types["jpg"] = AssetType::Texture;
s_Types["jpeg"] = AssetType::Texture;
s_Types["bmp"] = AssetType::Texture;
s_Types["tga"] = AssetType::Texture; s_Types["tga"] = AssetType::Texture;
s_Types["hdr"] = AssetType::EnvMap; s_Types["hdr"] = AssetType::EnvMap;
s_Types["blend"] = AssetType::Mesh; s_Types["blend"] = AssetType::Mesh;
s_Types["pmat"] = AssetType::Material;
s_Types["hpm"] = AssetType::PhysicsMaterial; s_Types["hpm"] = AssetType::PhysicsMaterial;
s_Types["wav"] = AssetType::Audio; s_Types["wav"] = AssetType::Audio;
s_Types["ogg"] = AssetType::Audio; s_Types["ogg"] = AssetType::Audio;
@ -132,25 +137,6 @@ namespace Prism
return assetHandle != 0 && s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end(); return assetHandle != 0 && s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end();
} }
void AssetsManager::Rename(Ref<Asset>& asset, const std::string& newName)
{
const std::string newFilePath = FileSystem::Rename(asset->FilePath, newName);
const std::string oldFilePath = asset->FilePath;
asset->FilePath = newFilePath;
asset->FileName = newName;
if (FileSystem::Exists(oldFilePath + ".meta"))
{
std::string metaFileName = oldFilePath;
if (!asset->Extension.empty())
metaFileName += "." + asset->Extension;
FileSystem::PrismDeleteFile(oldFilePath + ".meta");
AssetSerializer::CreateMetaFile(asset);
}
}
template <typename T> template <typename T>
Ref<T> AssetsManager::GetAsset(AssetHandle assetHandle, bool loadData) Ref<T> AssetsManager::GetAsset(AssetHandle assetHandle, bool loadData)
{ {
@ -169,7 +155,7 @@ namespace Prism
template PRISM_API Ref<Asset> AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref<Asset> AssetsManager::GetAsset(AssetHandle, bool);
template PRISM_API Ref<Mesh> AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref<Mesh> AssetsManager::GetAsset(AssetHandle, bool);
template PRISM_API Ref<PhysicsMaterial> AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref<PhysicsMaterialAsset> AssetsManager::GetAsset(AssetHandle, bool);
template PRISM_API Ref<Environment> AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref<Environment> AssetsManager::GetAsset(AssetHandle, bool);
template PRISM_API Ref<Directory> AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref<Directory> AssetsManager::GetAsset(AssetHandle, bool);
template PRISM_API Ref<Texture2D> AssetsManager::GetAsset(AssetHandle, bool); template PRISM_API Ref<Texture2D> AssetsManager::GetAsset(AssetHandle, bool);
@ -180,35 +166,30 @@ namespace Prism
return GetAsset<T>(GetAssetHandleFromFilePath(filepath), loadData); return GetAsset<T>(GetAssetHandleFromFilePath(filepath), loadData);
} }
template PRISM_API Ref<Asset> AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref<Asset> AssetsManager::GetAsset(const std::string&, bool);
template PRISM_API Ref<Mesh> AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref<Mesh> AssetsManager::GetAsset(const std::string&, bool);
template PRISM_API Ref<PhysicsMaterial> AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref<PhysicsMaterialAsset> AssetsManager::GetAsset(const std::string&, bool);
template PRISM_API Ref<PBRMaterialAsset> AssetsManager::GetAsset(const std::string&, bool);
template PRISM_API Ref<Environment> AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref<Environment> AssetsManager::GetAsset(const std::string&, bool);
template PRISM_API Ref<Directory> AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref<Directory> AssetsManager::GetAsset(const std::string&, bool);
template PRISM_API Ref<Texture2D> AssetsManager::GetAsset(const std::string&, bool); template PRISM_API Ref<Texture2D> AssetsManager::GetAsset(const std::string&, bool);
template <typename T>
// temp Ref<T> AssetsManager::TryGetAsset(const std::string& filepath, const bool loadData)
Ref<PhysicsMaterial> AssetsManager::CreateAssetPhysicsMaterial(const std::string& filename, const AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3)
{ {
AssetHandle assetHandle = GetAssetHandleFromFilePath(filepath);
const auto& directory = GetAsset<Directory>(directoryHandle); if (!assetHandle) return Ref<T>();
return GetAsset<T>(assetHandle, loadData);
Ref<PhysicsMaterial> asset = Ref<PhysicsMaterial>::Create(v1, v2, v3);
asset->Type = type;
asset->FilePath = directory->FilePath + "/" + filename;
asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath));
asset->Extension = Utils::GetFilename(filename);
asset->ParentDirectory = directoryHandle;
asset->Handle = std::hash<std::string>()(asset->FilePath);
asset->IsDataLoaded = true;
s_LoadedAssets[asset->Handle] = asset;
AssetSerializer::SerializeAsset(asset);
AssetSerializer::CreateMetaFile(asset);
return asset;
} }
template PRISM_API Ref<Asset> AssetsManager::TryGetAsset(const std::string&, bool);
template PRISM_API Ref<Mesh> AssetsManager::TryGetAsset(const std::string&, bool);
template PRISM_API Ref<PhysicsMaterialAsset> AssetsManager::TryGetAsset(const std::string&, bool);
template PRISM_API Ref<PBRMaterialAsset> AssetsManager::TryGetAsset(const std::string&, bool);
template PRISM_API Ref<Environment> AssetsManager::TryGetAsset(const std::string&, bool);
template PRISM_API Ref<Directory> AssetsManager::TryGetAsset(const std::string&, bool);
template PRISM_API Ref<Texture2D> AssetsManager::TryGetAsset(const std::string&, bool);
void AssetsManager::RemoveAsset(AssetHandle assetHandle) void AssetsManager::RemoveAsset(AssetHandle assetHandle)
{ {
@ -252,7 +233,8 @@ namespace Prism
asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath)); asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath));
asset->Extension = Utils::GetFilename(filename); asset->Extension = Utils::GetFilename(filename);
asset->ParentDirectory = directoryHandle; asset->ParentDirectory = directoryHandle;
asset->Handle = std::hash<std::string>()(asset->FilePath); asset->Handle = std::hash<std::string>()(asset->FilePath + std::to_string(Application::Get().GetTime()));
asset->IsDataLoaded = true; asset->IsDataLoaded = true;
s_LoadedAssets[asset->Handle] = asset; s_LoadedAssets[asset->Handle] = asset;
@ -262,6 +244,10 @@ namespace Prism
return asset; return asset;
} }
template PRISM_API Ref<PhysicsMaterialAsset> AssetsManager::CreateAsset<PhysicsMaterialAsset, float, float, float>(const std::string&, AssetType, AssetHandle, float&&, float&&, float&&);
template PRISM_API Ref<PhysicsMaterialAsset> AssetsManager::CreateAsset<PhysicsMaterialAsset>( const std::string&, AssetType, AssetHandle);
template PRISM_API Ref<PBRMaterialAsset> AssetsManager::CreateAsset<PBRMaterialAsset>( const std::string&, AssetType, AssetHandle);
bool AssetsManager::IsAssetType(const AssetHandle assetHandle, const AssetType type) bool AssetsManager::IsAssetType(const AssetHandle assetHandle, const AssetType type)
@ -307,7 +293,7 @@ namespace Prism
{ {
const std::string extension = Utils::GetExtension(filepath); const std::string extension = Utils::GetExtension(filepath);
if (extension == "meta") if (extension == "meta")
return Ref<Asset>(); return {};
const AssetType type = AssetTypes::GetAssetTypeFromExtension(extension); const AssetType type = AssetTypes::GetAssetTypeFromExtension(extension);
Ref<Asset> asset = AssetSerializer::LoadAssetInfo(filepath, parentHandle, type); Ref<Asset> asset = AssetSerializer::LoadAssetInfo(filepath, parentHandle, type);
@ -368,7 +354,9 @@ namespace Prism
ProcessDirectory(e.FilePath, parentHandle); ProcessDirectory(e.FilePath, parentHandle);
else else
{ {
Ref<Asset> asset = ImportAsset(e.FilePath, parentHandle); AssetHandle assetHandle = GetAssetHandleFromFilePath(e.FilePath);
if (!assetHandle)
ImportAsset(e.FilePath, parentHandle);
} }
} }
@ -383,41 +371,32 @@ namespace Prism
break; break;
case FileSystemAction::Rename: case FileSystemAction::Rename:
{ {
Ref<Asset> asset; Ref<Asset> asset = nullptr;
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
{ {
if (it->second->FileName == e.OldName) const std::string oldFilePath = Utils::ReplaceFilePathName(e.FilePath, e.OldName);
for (auto& [handle, existingAsset] : s_LoadedAssets)
{ {
asset = it->second; if (existingAsset->FilePath == oldFilePath)
{
asset = existingAsset;
break;
}
} }
} }
if (asset) if (asset)
{ {
if (asset->Type != AssetTypes::GetAssetTypeFromExtension(Utils::GetExtension(e.FilePath))) std::string extension = Utils::GetExtension(asset->FilePath);
{ std::string oldMetaPath = asset->FilePath + ".meta";
RemoveAsset(asset->Handle);
FileSystem::PrismDeleteFile(asset->FilePath + ".meta");
asset = ImportAsset(e.FilePath, parentHandle);
}else
{
std::string oldMetaPath = asset->FilePath + ".meta";
std::string newMetaPath = e.FilePath + ".meta";
std::error_code ec; FileSystem::Rename(oldMetaPath, e.NewName + "." + extension);
std::filesystem::rename(oldMetaPath, newMetaPath, ec);
if (ec)
{
PM_CORE_ERROR("Failed to rename meta file: {}", ec.message());
}
asset->FilePath = e.FilePath; asset->FilePath = e.FilePath;
asset->FileName = e.NewName; asset->FileName = e.NewName;
} asset->Extension = extension;
}
AssetSerializer::UpdateMetaFile(asset);
}
} }
break; break;
case FileSystemAction::Delete: case FileSystemAction::Delete:

View File

@ -45,9 +45,8 @@ namespace Prism
static AssetHandle GetAssetHandleFromFilePath(const std::string& filepath); static AssetHandle GetAssetHandleFromFilePath(const std::string& filepath);
static bool IsAssetHandleValid(const AssetHandle& assetHandle); static bool IsAssetHandleValid(const AssetHandle& assetHandle);
static void Rename(Ref<Asset>& asset, const std::string& newName);
static Ref<PhysicsMaterial> CreateAssetPhysicsMaterial(const std::string& filename, AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3); static Ref<PhysicsMaterialAsset> CreateAssetPhysicsMaterial(const std::string& filename, AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3);
static void RemoveAsset(AssetHandle assetHandle); static void RemoveAsset(AssetHandle assetHandle);
@ -59,6 +58,8 @@ namespace Prism
template<typename T> template<typename T>
static Ref<T> GetAsset(const std::string& filepath, bool loadData = true); static Ref<T> GetAsset(const std::string& filepath, bool loadData = true);
template <class T>
static Ref<T> TryGetAsset(const std::string& filepath, bool loadData = true);
static bool IsAssetType(AssetHandle assetHandle, AssetType type); static bool IsAssetType(AssetHandle assetHandle, AssetType type);

View File

@ -36,7 +36,6 @@ namespace Prism
m_Window = std::unique_ptr<Window>(Window::Create(WindowProps{props.Name, props.Width, props.Height})); m_Window = std::unique_ptr<Window>(Window::Create(WindowProps{props.Name, props.Width, props.Height}));
m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent)); m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent));
m_Window->SetVSync(true); m_Window->SetVSync(true);
m_Window->Maximize();
m_ImGuiLayer = new ImGuiLayer("ImGui Layer"); m_ImGuiLayer = new ImGuiLayer("ImGui Layer");
PushOverlay(m_ImGuiLayer); PushOverlay(m_ImGuiLayer);
@ -107,6 +106,7 @@ namespace Prism
for (Layer* layer : m_LayerStack) for (Layer* layer : m_LayerStack)
layer->OnImGuiRender(); layer->OnImGuiRender();
/*
ImGui::Begin("Renderer"); ImGui::Begin("Renderer");
const auto& caps = RendererAPI::GetCapabilities(); const auto& caps = RendererAPI::GetCapabilities();
ImGui::Text("Vendor: %s", caps.Vendor.c_str()); ImGui::Text("Vendor: %s", caps.Vendor.c_str());
@ -114,6 +114,7 @@ namespace Prism
ImGui::Text("Version: %s", caps.Version.c_str()); ImGui::Text("Version: %s", caps.Version.c_str());
ImGui::Text("Frame Time: %.2fms\n", m_TimeStep.GetMilliseconds()); ImGui::Text("Frame Time: %.2fms\n", m_TimeStep.GetMilliseconds());
ImGui::End(); ImGui::End();
*/
m_ImGuiLayer->End(); m_ImGuiLayer->End();
} }

View File

@ -12,7 +12,19 @@
extern Prism::Application* Prism::CreateApplication(CommandArgs args); extern Prism::Application* Prism::CreateApplication(CommandArgs args);
int main(int argc, char** argv) #ifdef PRISM_GUI
#ifdef _WIN32
#include <windows.h>
int MainEntry(int argc, char* argv[]);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
return MainEntry(__argc, __argv);
}
#endif
int MainEntry(int argc, char** argv)
#else
int main(int argc, char** argv)
#endif
{ {
//TODO: this will use other method to impl //TODO: this will use other method to impl
std::cout << std::filesystem::current_path() << std::endl; std::cout << std::filesystem::current_path() << std::endl;
@ -33,6 +45,7 @@ int main(int argc, char** argv)
Prism::ShutdownCore(); Prism::ShutdownCore();
#endif #endif
return 0;
} }
#endif //ENTRYPOINT_H #endif //ENTRYPOINT_H

View File

@ -45,6 +45,49 @@ namespace Prism {
EVENT_CLASS_CATEGORY(EventCategoryApplication) EVENT_CLASS_CATEGORY(EventCategoryApplication)
}; };
class PRISM_API WindowFocusEvent : public Event
{
public:
WindowFocusEvent() = default;
EVENT_CLASS_TYPE(WindowFocus)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
};
class PRISM_API WindowLostFocusEvent : public Event
{
public:
WindowLostFocusEvent() = default;
EVENT_CLASS_TYPE(WindowLostFocus)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
};
class PRISM_API WindowMovedEvent : public Event
{
public:
WindowMovedEvent(const int32_t x, const int32_t y)
: m_X(x), m_Y(y)
{
}
inline int32_t GetX() const { return m_X; }
inline int32_t GetY() const { return m_Y; }
std::string ToString() const override
{
std::stringstream ss;
ss << "WindowMovedEvent: " << m_X << ", " << m_Y;
return ss.str();
}
EVENT_CLASS_TYPE(WindowMoved)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
private:
int32_t m_X, m_Y;
};
class PRISM_API AppTickEvent : public Event class PRISM_API AppTickEvent : public Event
{ {
public: public:

View File

@ -24,7 +24,6 @@ namespace Prism
static std::shared_ptr<spdlog::logger> s_CoreLogger; static std::shared_ptr<spdlog::logger> s_CoreLogger;
static std::shared_ptr<spdlog::logger> s_ClientLogger; static std::shared_ptr<spdlog::logger> s_ClientLogger;
}; };
}
#ifdef _DEBUG #ifdef _DEBUG
#define PM_CORE_TRACE(...) SPDLOG_LOGGER_TRACE(::Prism::Log::GetCoreLogger(), __VA_ARGS__) #define PM_CORE_TRACE(...) SPDLOG_LOGGER_TRACE(::Prism::Log::GetCoreLogger(), __VA_ARGS__)
@ -41,6 +40,8 @@ namespace Prism
#define PM_CORE_ERROR(...) ::Prism::Log::GetCoreLogger()->error(__VA_ARGS__) #define PM_CORE_ERROR(...) ::Prism::Log::GetCoreLogger()->error(__VA_ARGS__)
#define PM_CORE_FATAL(...) ::Prism::Log::GetCoreLogger()->critical(__VA_ARGS__) #define PM_CORE_FATAL(...) ::Prism::Log::GetCoreLogger()->critical(__VA_ARGS__)
#endif #endif
}
#define PM_CLIENT_TRACE(...) ::Prism::Log::GetClientLogger()->trace(__VA_ARGS__) #define PM_CLIENT_TRACE(...) ::Prism::Log::GetClientLogger()->trace(__VA_ARGS__)

View File

@ -19,6 +19,10 @@ namespace Prism
AABB(const glm::vec3& min, const glm::vec3& max) AABB(const glm::vec3& min, const glm::vec3& max)
: Min(min), Max(max) {} : Min(min), Max(max) {}
bool IsValid() const {
return Min.x <= Max.x && Min.y <= Max.y && Min.z <= Max.z;
}
}; };
} }

View File

@ -21,7 +21,7 @@ namespace Prism
operator float() { return m_Time; } operator float() { return m_Time; }
private: private:
float m_Time; float m_Time = 0.0f;
}; };
} }

View File

@ -10,6 +10,7 @@
#include "Ref.h" #include "Ref.h"
#include "Events/Event.h" #include "Events/Event.h"
#include "Prism/Core/Core.h" #include "Prism/Core/Core.h"
#include <glm/glm.hpp>
namespace Prism namespace Prism
@ -39,8 +40,8 @@ namespace Prism
virtual void SetEventCallback(const EventCallbackFn& callback) = 0; virtual void SetEventCallback(const EventCallbackFn& callback) = 0;
virtual uint32_t GetWidth() const = 0; virtual uint32_t GetWidth() const = 0;
virtual uint32_t GetHeight() const = 0; virtual uint32_t GetHeight() const = 0;
virtual std::pair<uint32_t, uint32_t> GetSize() const = 0; virtual glm::ivec2 GetSize() const = 0;
virtual std::pair<float, float> GetWindowPos() const = 0; virtual glm::vec2 GetWindowPos() const = 0;
virtual void SetVSync(bool enable) = 0; virtual void SetVSync(bool enable) = 0;
virtual bool const IsVSync() const = 0; virtual bool const IsVSync() const = 0;

View File

@ -52,6 +52,7 @@ namespace Prism
{ {
RegisterEditor<TextureViewer>(AssetType::Texture); RegisterEditor<TextureViewer>(AssetType::Texture);
RegisterEditor<PhysicsMaterialEditor>(AssetType::PhysicsMaterial); RegisterEditor<PhysicsMaterialEditor>(AssetType::PhysicsMaterial);
RegisterEditor<PBRMaterialEditor>(AssetType::Material);
} }
void AssetEditorPanel::OnImGuiRender() void AssetEditorPanel::OnImGuiRender()
@ -62,6 +63,11 @@ namespace Prism
void AssetEditorPanel::OpenEditor(const Ref<Asset>& asset) void AssetEditorPanel::OpenEditor(const Ref<Asset>& asset)
{ {
if (!asset)
{
PM_CORE_WARN("asset is Invalid!");
return;
}
if (s_Editors.find(asset->Type) == s_Editors.end()) if (s_Editors.find(asset->Type) == s_Editors.end())
{ {
PM_CORE_WARN("No editor registered for {0} assets", asset->Extension); PM_CORE_WARN("No editor registered for {0} assets", asset->Extension);

View File

@ -11,6 +11,7 @@
#include "Prism/Core/Application.h" #include "Prism/Core/Application.h"
#include "Prism/Core/Input.h" #include "Prism/Core/Input.h"
#include "Prism/Core/Log.h" #include "Prism/Core/Log.h"
#include "Prism/Utilities/StringUtils.h"
namespace Prism namespace Prism
{ {
@ -32,7 +33,9 @@ namespace Prism
m_AssetIconMap["blend"] = AssetsManager::GetAsset<Texture2D>("assets/editor/blend.png"); m_AssetIconMap["blend"] = AssetsManager::GetAsset<Texture2D>("assets/editor/blend.png");
// TODO: get a logo for this project // TODO: get a logo for this project
m_AssetIconMap["scene"] = Texture2D::Create("assets/editor/asset.png"); m_AssetIconMap["scene"] = AssetsManager::GetAsset<Texture2D>("assets/editor/asset.png");
m_AssetIconMap["pmat"] = AssetsManager::GetAsset<Texture2D>("assets/editor/asset.png");
m_BackbtnTex = AssetsManager::GetAsset<Texture2D>("assets/editor/btn_back.png"); m_BackbtnTex = AssetsManager::GetAsset<Texture2D>("assets/editor/btn_back.png");
m_FwrdbtnTex = AssetsManager::GetAsset<Texture2D>("assets/editor/btn_fwrd.png"); m_FwrdbtnTex = AssetsManager::GetAsset<Texture2D>("assets/editor/btn_fwrd.png");
@ -101,16 +104,56 @@ namespace Prism
if (ImGui::MenuItem("Folder")) if (ImGui::MenuItem("Folder"))
{ {
PM_CORE_INFO("Creating Folder..."); PM_CORE_INFO("Creating Folder...");
const bool created = FileSystem::CreateFolder(m_CurrentDirectory->FilePath + "/New Folder"); const std::string filePath = m_CurrentDirectory->FilePath + "/new folder";
if (created) FileSystem::CreateFolder(filePath);
UpdateCurrentDirectory(m_CurrentDirHandle);
}
if (ImGui::MenuItem("PBRMaterial"))
{
const std::string fileName = "Material.pmat";
const auto& directory = AssetsManager::GetAsset<Directory>(m_CurrentDirHandle);
// for hash UUID use
std::string baseName = Utils::RemoveExtension(fileName);
std::string extension = Utils::GetExtension(fileName, true);
std::string finalFilename = fileName;
std::string finalPath = directory->FilePath + "/" + finalFilename;
int counter = 1;
while (AssetsManager::GetAssetHandleFromFilePath(finalPath) != 0)
{ {
UpdateCurrentDirectory(m_CurrentDirHandle); finalFilename = baseName + "_" + std::to_string(counter++) + extension;
const auto& createdDirectory = AssetsManager::GetAsset<Directory>(AssetsManager::GetAssetHandleFromFilePath(m_CurrentDirectory->FilePath + "/New Folder")); finalPath = directory->FilePath + "/" + finalFilename;
m_SelectedAssets.Select(createdDirectory->Handle);
memset(m_InputBuffer, 0, MAX_INPUT_BUFFER_LENGTH);
memcpy(m_InputBuffer, createdDirectory->FileName.c_str(), createdDirectory->FileName.size());
m_RenamingSelected = true;
} }
AssetsManager::CreateAsset<PBRMaterialAsset>(finalFilename, AssetType::Material, m_CurrentDirHandle);
UpdateCurrentDirectory(m_CurrentDirHandle);
}
if (ImGui::MenuItem("Physics Material"))
{
const std::string fileName = "PhysicsMaterial.hpm";
const auto& directory = AssetsManager::GetAsset<Directory>(m_CurrentDirHandle);
// for hash UUID use
std::string baseName = Utils::RemoveExtension(fileName);
std::string extension = Utils::GetExtension(fileName, true);
std::string finalFilename = fileName;
std::string finalPath = directory->FilePath + "/" + finalFilename;
int counter = 1;
while (AssetsManager::GetAssetHandleFromFilePath(finalPath) != 0)
{
finalFilename = baseName + "_" + std::to_string(counter++) + extension;
finalPath = directory->FilePath + "/" + finalFilename;
}
AssetsManager::CreateAsset<PhysicsMaterialAsset>(finalFilename, AssetType::PhysicsMaterial, m_CurrentDirHandle, 0.6f, 0.6f, 0.0f);
UpdateCurrentDirectory(m_CurrentDirHandle);
} }
if (ImGui::MenuItem("Scene")) if (ImGui::MenuItem("Scene"))
@ -123,13 +166,23 @@ namespace Prism
PM_CORE_INFO("Creating Script..."); PM_CORE_INFO("Creating Script...");
} }
/*
if (ImGui::MenuItem("Prefab")) if (ImGui::MenuItem("Prefab"))
{ {
PM_CORE_INFO("Creating Prefab..."); PM_CORE_INFO("Creating Prefab...");
} }
*/
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::Separator();
if (ImGui::MenuItem("Open In Explorer"))
{
Ref<Asset> asset = AssetsManager::GetAsset<Asset>(m_CurrentDirHandle);
FileSystem::OpenInExplorer(asset->FilePath);
}
ImGui::Separator();
if (ImGui::MenuItem("Import")) if (ImGui::MenuItem("Import"))
{ {
@ -141,12 +194,6 @@ namespace Prism
UpdateCurrentDirectory(m_CurrentDirHandle); UpdateCurrentDirectory(m_CurrentDirHandle);
} }
if (ImGui::MenuItem("Physics Material"))
{
// TODO: use template
AssetsManager::CreateAssetPhysicsMaterial("New Physics Material.hpm", AssetType::PhysicsMaterial, m_CurrentDirHandle, 0.6f, 0.6f, 0.0f);
UpdateCurrentDirectory(m_CurrentDirHandle);
}
ImGui::EndPopup(); ImGui::EndPopup();
} }
@ -300,6 +347,12 @@ namespace Prism
if (ImGui::BeginPopupContextItem()) if (ImGui::BeginPopupContextItem())
{ {
if (ImGui::MenuItem("Open In Explorer"))
{
FileSystem::OpenInExplorer(asset->FilePath);
}
ImGui::Separator();
if (ImGui::MenuItem("Rename")) if (ImGui::MenuItem("Rename"))
{ {
m_SelectedAssets.Select(assetHandle); m_SelectedAssets.Select(assetHandle);
@ -523,7 +576,8 @@ namespace Prism
if (ImGui::InputText("##rename_dummy", m_InputBuffer, MAX_INPUT_BUFFER_LENGTH, ImGuiInputTextFlags_EnterReturnsTrue)) if (ImGui::InputText("##rename_dummy", m_InputBuffer, MAX_INPUT_BUFFER_LENGTH, ImGuiInputTextFlags_EnterReturnsTrue))
{ {
PM_CORE_INFO("Renaming to {0}", m_InputBuffer); PM_CORE_INFO("Renaming to {0}", m_InputBuffer);
AssetsManager::Rename(asset, m_InputBuffer); const std::string filename = m_InputBuffer;
FileSystem::Rename(asset->FilePath, filename);
m_RenamingSelected = false; m_RenamingSelected = false;
m_SelectedAssets.Clear(); m_SelectedAssets.Clear();
m_UpdateDirectoryNextFrame = true; m_UpdateDirectoryNextFrame = true;

View File

@ -13,6 +13,12 @@ namespace Prism
PhysicsMaterialEditor::PhysicsMaterialEditor() PhysicsMaterialEditor::PhysicsMaterialEditor()
: AssetEditor("Edit Physics Material") {} : AssetEditor("Edit Physics Material") {}
void PhysicsMaterialEditor::SetAsset(const Ref<Asset>& asset)
{
if (m_Asset) AssetSerializer::SerializeAsset(m_Asset);
m_Asset = static_cast<Ref<PhysicsMaterialAsset>>(asset);
}
void PhysicsMaterialEditor::Render() void PhysicsMaterialEditor::Render()
{ {
if (!m_Asset) if (!m_Asset)
@ -37,6 +43,12 @@ namespace Prism
SetMaxSize(500, 1000); SetMaxSize(500, 1000);
} }
void TextureViewer::SetAsset(const Ref<Asset>& asset)
{
if (m_Asset) AssetSerializer::SerializeAsset(m_Asset);
m_Asset = static_cast<Ref<Texture>>(asset);
}
void TextureViewer::Render() void TextureViewer::Render()
{ {
if (!m_Asset) if (!m_Asset)
@ -58,4 +70,214 @@ namespace Prism
UI::EndPropertyGrid(); UI::EndPropertyGrid();
} }
PBRMaterialEditor::PBRMaterialEditor() : AssetEditor("Material Editor")
{
}
// 辅助函数:绘制纹理拖拽槽
void DrawTextureSlot(Ref<Texture2D>& texture, const std::function<void(Ref<Texture2D>)>& onDrop)
{
static Ref<Texture2D> s_Checkerboard = nullptr;
if (!s_Checkerboard)
s_Checkerboard = AssetsManager::GetAsset<Texture2D>("assets/editor/Checkerboard.tga");
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image(texture ? (ImTextureID)(intptr_t)texture->GetRendererID() : (ImTextureID)(intptr_t)s_Checkerboard->GetRendererID(),
ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::BeginDragDropTarget())
{
if (const auto data = ImGui::AcceptDragDropPayload("asset_payload"))
{
AssetHandle assetHandle = *(AssetHandle*)data->Data;
if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture))
{
Ref<Texture2D> newTex = AssetsManager::GetAsset<Texture2D>(assetHandle);
if (onDrop) onDrop(newTex);
}
}
ImGui::EndDragDropTarget();
}
if (ImGui::IsItemHovered())
{
if (texture)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(texture->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureID)(intptr_t)texture->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
/*
// TODO: how to solve this
if (ImGui::IsItemClicked(ImGuiMouseButton_Left))
{
std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg");
if (!filename.empty())
{
Ref<Texture2D> newTex = Texture2D::Create(filename);
if (onDrop) onDrop(newTex);
}
}
*/
}
}
void PBRMaterialEditor::SetAsset(const Ref<Asset>& asset)
{
if (m_Asset)
{
if (m_Asset->Handle == asset->Handle) return;
if (AssetsManager::IsAssetHandleValid(m_Asset->Handle))
AssetSerializer::SerializeAsset(m_Asset);
}
m_Asset = static_cast<Ref<PBRMaterialAsset>>(asset);
}
void PBRMaterialEditor::Render()
{
if (!m_Asset) return;
auto& material = m_Asset;
if (ImGui::BeginTabBar("MaterialProperties", ImGuiTabBarFlags_None))
{
// ==================== Parameters ====================
if (ImGui::BeginTabItem("Parameters"))
{
ImGui::Spacing();
if (ImGui::CollapsingHeader("Albedo", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Indent();
if (ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(material->AlbedoColor)))
{
m_Asset->IsDirty = true;
}
bool useAlbedoMap = (material->AlbedoTexToggle > 0.5f);
if (ImGui::Checkbox("Use Texture##Albedo", &useAlbedoMap))
{
material->AlbedoTexToggle = useAlbedoMap ? 1.0f : 0.0f;
m_Asset->IsDirty = true;
}
DrawTextureSlot(material->AlbedoTexture, [&](const Ref<Texture2D>& newTex) {
material->AlbedoTexture = newTex;
material->AlbedoTexToggle = true;
m_Asset->IsDirty = true;
});
ImGui::SameLine();
ImGui::Text("Albedo Texture");
ImGui::Unindent();
}
// Normal Map
if (ImGui::CollapsingHeader("Normal Map", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Indent();
bool useNormalMap = (material->NormalTexToggle > 0.5f);
if (ImGui::Checkbox("Use Texture##Normal", &useNormalMap))
{
material->NormalTexToggle = useNormalMap ? 1.0f : 0.0f;
m_Asset->IsDirty = true;
}
DrawTextureSlot(material->NormalTexture, [&](const Ref<Texture2D>& newTex) {
material->NormalTexture = newTex;
material->NormalTexToggle = true;
m_Asset->IsDirty = true;
});
ImGui::SameLine();
ImGui::Text("Normal Texture");
ImGui::Unindent();
}
// Metalness
if (ImGui::CollapsingHeader("Metalness", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Indent();
if (ImGui::SliderFloat("Value##Metalness", &material->Metalness, 0.0f, 1.0f))
{
// 自动保存
m_Asset->IsDirty = true;
}
bool useMetalnessMap = (material->MetalnessTexToggle > 0.5f);
if (ImGui::Checkbox("Use Texture##Metalness", &useMetalnessMap))
{
material->MetalnessTexToggle = useMetalnessMap ? 1.0f : 0.0f;
m_Asset->IsDirty = true;
}
DrawTextureSlot(material->MetalnessTexture, [&](const Ref<Texture2D>& newTex) {
material->MetalnessTexture = newTex;
material->MetalnessTexToggle = true;
m_Asset->IsDirty = true;
});
ImGui::SameLine();
ImGui::Text("Metalness Texture");
ImGui::Unindent();
}
// Roughness
if (ImGui::CollapsingHeader("Roughness", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Indent();
if (ImGui::SliderFloat("Value##Roughness", &material->Roughness, 0.0f, 1.0f))
{
// 自动保存
m_Asset->IsDirty = true;
}
bool useRoughnessMap = (material->RoughnessTexToggle > 0.5f);
if (ImGui::Checkbox("Use Texture##Roughness", &useRoughnessMap))
{
material->RoughnessTexToggle = useRoughnessMap ? 1.0f : 0.0f;
m_Asset->IsDirty = true;
}
DrawTextureSlot(material->RoughnessTexture, [&](const Ref<Texture2D>& newTex) {
material->RoughnessTexture = newTex;
material->RoughnessTexToggle = true;
m_Asset->IsDirty = true;
});
ImGui::SameLine();
ImGui::Text("Roughness Texture");
ImGui::Unindent();
}
ImGui::EndTabItem();
}
// ==================== 预览 ====================
if (ImGui::BeginTabItem("Preview"))
{
// 简单显示纹理预览
if (material->AlbedoTexture)
{
ImGui::Text("Albedo Preview");
ImGui::Image((ImTextureID)(intptr_t)material->AlbedoTexture->GetRendererID(), ImVec2(128, 128));
}
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
} }

View File

@ -15,14 +15,14 @@ namespace Prism
public: public:
PhysicsMaterialEditor(); PhysicsMaterialEditor();
virtual Ref<Asset> GetAsset() override { return m_Asset; } Ref<Asset> GetAsset() override { return m_Asset; }
virtual void SetAsset(const Ref<Asset>& asset) override { m_Asset = (Ref<PhysicsMaterial>)asset; } void SetAsset(const Ref<Asset>& asset) override;
private: private:
virtual void Render() override; void Render() override;
private: private:
Ref<PhysicsMaterial> m_Asset; Ref<PhysicsMaterialAsset> m_Asset;
}; };
class TextureViewer : public AssetEditor class TextureViewer : public AssetEditor
@ -30,16 +30,31 @@ namespace Prism
public: public:
TextureViewer(); TextureViewer();
virtual Ref<Asset> GetAsset() override { return m_Asset; } Ref<Asset> GetAsset() override { return m_Asset; }
virtual void SetAsset(const Ref<Asset>& asset) override { m_Asset = static_cast<Ref<Texture>>(asset); } void SetAsset(const Ref<Asset>& asset) override;
private: private:
virtual void Render() override; void Render() override;
private: private:
Ref<Texture> m_Asset; Ref<Texture> m_Asset;
}; };
class PBRMaterialEditor : public AssetEditor
{
public:
PBRMaterialEditor();
Ref<Asset> GetAsset() override { return m_Asset; }
void SetAsset(const Ref<Asset>& asset) override;
private:
void Render() override;
private:
Ref<PBRMaterialAsset> m_Asset;
};
} }
#endif //PRISM_DEFAULTASSETEDITORS_H #endif //PRISM_DEFAULTASSETEDITORS_H

View File

@ -14,6 +14,7 @@
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
#include <glm/gtx/matrix_decompose.hpp> #include <glm/gtx/matrix_decompose.hpp>
#include "AssetEditorPanel.h"
#include "Prism/Core/Application.h" #include "Prism/Core/Application.h"
#include "Prism/Core/Math/Math.h" #include "Prism/Core/Math/Math.h"
#include "Prism/Physics/PhysicsLayer.h" #include "Prism/Physics/PhysicsLayer.h"
@ -547,7 +548,7 @@ namespace Prism
template<typename T, typename UIFunction> template<typename T, typename UIFunction>
static void DrawComponent(const std::string& name, Entity entity, UIFunction uiFunction) static void DrawComponent(const std::string& name, Entity entity, UIFunction uiFunction)
{ {
const ImGuiTreeNodeFlags treeNodeFlags = ImGuiTreeNodeFlags_DefaultOpen | constexpr ImGuiTreeNodeFlags treeNodeFlags = ImGuiTreeNodeFlags_DefaultOpen |
ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_Framed |
ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanAvailWidth |
ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_AllowOverlap |
@ -886,13 +887,50 @@ namespace Prism
DrawComponent<MeshComponent>("Mesh", entity, [](MeshComponent& meshComponent) { DrawComponent<MeshComponent>("Mesh", entity, [](MeshComponent& meshComponent) {
UI::BeginPropertyGrid(); UI::BeginPropertyGrid();
UI::PropertyAssetReference("Mesh", meshComponent.Mesh, AssetType::Mesh);
// UI::Property("AnimationPlaying", meshComponent.Mesh->m_AnimationPlaying);
// UI::Property("TimeMultiple", meshComponent.Mesh->m_TimeMultiplier);
// UI::Property("AnimationTime", meshComponent.Mesh->m_AnimationTime);
// UI::Property("WorldTime", meshComponent.Mesh->m_WorldTime);
if (UI::PropertyAssetReference("Mesh", meshComponent.Mesh, AssetType::Mesh))
{
meshComponent.MaterialInstances.clear();
meshComponent.MaterialDescs.clear();
const auto& materialInstances = meshComponent.Mesh->GetMaterials();
for (uint32_t i = 0; i < materialInstances.size(); i++)
{
Ref<MaterialInstance> materialInstance = MaterialInstance::Copy(materialInstances[i]);
meshComponent.MaterialInstances.push_back(materialInstance);
}
meshComponent.MaterialDescs.resize(materialInstances.size());
}
UI::EndPropertyGrid(); UI::EndPropertyGrid();
for (auto i = 0; i < meshComponent.MaterialDescs.size(); i++)
{
// TODO: 这里通过 MaterialDesc进行存储信息然后修改后由此处更新MaterialInstances同时还缺少一个在MeshComponent中MaterialDesc的序列化
if (UI::BeginTreeNode((std::string("Slot ") + std::to_string(i)).c_str()))
{
UI::BeginPropertyGrid();
if (meshComponent.MaterialDescs[i])
{
if (ImGui::Button("X"))
{
meshComponent.MaterialDescs[i] = nullptr;
meshComponent.UpdateMaterials(i);
}
ImGui::SameLine();
}
if (ImGui::Button("Edit")) AssetEditorPanel::OpenEditor(meshComponent.MaterialDescs[i]);
ImGui::SameLine();
if (UI::PropertyAssetReference(meshComponent.MaterialInstances[i]->GetName().c_str(), meshComponent.MaterialDescs[i], AssetType::Material))
{
meshComponent.UpdateMaterials(-1, true);
}
UI::EndPropertyGrid();
UI::EndTreeNode();
}
}
}); });
DrawComponent<AnimationComponent>("AnimatorController", entity, [this](AnimationComponent& animatorComponent) DrawComponent<AnimationComponent>("AnimatorController", entity, [this](AnimationComponent& animatorComponent)
@ -1090,18 +1128,33 @@ namespace Prism
}); });
DrawComponent<ScriptComponent>("Script", entity, [=](ScriptComponent& scriptComponent) mutable { DrawComponent<ScriptComponent>("Script", entity, [=](ScriptComponent& scriptComponent) mutable {
UI::BeginPropertyGrid();
const std::string oldName = scriptComponent.ModuleName;
if (UI::Property("Module Name", scriptComponent.ModuleName, !ScriptEngine::ModuleExists(scriptComponent.ModuleName))) // TODO: no live edit
{
// Shutdown old script
if (ScriptEngine::ModuleExists(oldName))
ScriptEngine::ShutdownScriptEntity(entity, oldName);
if (ScriptEngine::ModuleExists(scriptComponent.ModuleName)) const std::string oldName = scriptComponent.ModuleName;
ScriptEngine::InitScriptEntity(entity);
if (ImGui::BeginCombo("Module Name", scriptComponent.ModuleName.c_str()))
{
const auto& availableScripts = ScriptEngine::GetAvailableScripts();
for (const auto& script : availableScripts)
{
const bool isSelected = (scriptComponent.ModuleName == script);
if (ImGui::Selectable(script.c_str(), isSelected))
{
// 切换逻辑
if (ScriptEngine::ModuleExists(oldName))
ScriptEngine::ShutdownScriptEntity(entity, oldName);
scriptComponent.ModuleName = script;
if (ScriptEngine::ModuleExists(scriptComponent.ModuleName))
ScriptEngine::InitScriptEntity(entity);
}
if (isSelected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
} }
UI::BeginPropertyGrid();
// Public Fields // Public Fields
if (ScriptEngine::ModuleExists(scriptComponent.ModuleName)) if (ScriptEngine::ModuleExists(scriptComponent.ModuleName))
{ {
@ -1345,7 +1398,7 @@ namespace Prism
if (UI::Property("Size", bcc.Size)) if (UI::Property("Size", bcc.Size))
{ {
bcc.DebugMesh = MeshFactory::CreateBox(bcc.Size); bcc.DebugMesh = MeshFactory::CreateBox(bcc.Size * 2.0f);
} }
UI::Property("IsTrigger", bcc.IsTrigger); UI::Property("IsTrigger", bcc.IsTrigger);

View File

@ -85,7 +85,8 @@ namespace Prism
void Physics3D::Simulate(const TimeStep ts) void Physics3D::Simulate(const TimeStep ts)
{ {
auto& time = s_SimulationTime;
auto& sett = s_Settings;
// TODO: Allow projects to control the fixed step amount // TODO: Allow projects to control the fixed step amount
s_SimulationTime += ts.GetMilliseconds(); s_SimulationTime += ts.GetMilliseconds();
@ -106,7 +107,7 @@ namespace Prism
void Physics3D::DestroyScene() void Physics3D::DestroyScene()
{ {
PM_CORE_ASSERT(s_Scene); if (!s_Scene) return;
s_Actors.clear(); s_Actors.clear();
s_Scene->release(); s_Scene->release();

View File

@ -11,6 +11,8 @@
#include "Prism/Script/ScriptEngine.h" #include "Prism/Script/ScriptEngine.h"
#include <glm/gtx/compatibility.hpp> #include <glm/gtx/compatibility.hpp>
#include "glm/gtx/euler_angles.hpp"
namespace Prism namespace Prism
{ {
PhysicsActor::PhysicsActor(Entity entity) PhysicsActor::PhysicsActor(Entity entity)
@ -177,15 +179,24 @@ namespace Prism
Ref<Scene> scene = Scene::GetScene(m_Entity.GetSceneUUID()); Ref<Scene> scene = Scene::GetScene(m_Entity.GetSceneUUID());
glm::mat4 transform = scene->GetTransformRelativeToParent(m_Entity); glm::mat4 transform = scene->GetTransformRelativeToParent(m_Entity);
if (m_RigidBody.BodyType == RigidBodyComponent::Type::Static) glm::vec3 translation, rotationEuler, scale;
{ Math::DecomposeTransform(transform, translation, rotationEuler, scale);
m_ActorInternal = physics.createRigidStatic(ToPhysXTransform(transform));
} const glm::mat4 rotMat = glm::eulerAngleYXZ(rotationEuler.y, rotationEuler.x, rotationEuler.z);
else const glm::quat rotationQuat = glm::quat_cast(rotMat);
physx::PxTransform pxTransform(ToPhysXVector(translation), ToPhysXQuat(rotationQuat));
// PhysicsActor::Initialize 中
m_WorldScale = scale;
if (IsDynamic())
{ {
const PhysicsSettings& settings = Physics3D::GetSettings(); const PhysicsSettings& settings = Physics3D::GetSettings();
physx::PxRigidDynamic* actor = physics.createRigidDynamic(ToPhysXTransform(transform)); physx::PxRigidDynamic* actor = physics.createRigidDynamic(pxTransform);
actor->setLinearDamping(m_RigidBody.LinearDrag); actor->setLinearDamping(m_RigidBody.LinearDrag);
actor->setAngularDamping(m_RigidBody.AngularDrag); actor->setAngularDamping(m_RigidBody.AngularDrag);
actor->setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, m_RigidBody.IsKinematic); actor->setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, m_RigidBody.IsKinematic);
@ -198,15 +209,26 @@ namespace Prism
actor->setActorFlag(physx::PxActorFlag::eDISABLE_GRAVITY, m_RigidBody.DisableGravity); actor->setActorFlag(physx::PxActorFlag::eDISABLE_GRAVITY, m_RigidBody.DisableGravity);
actor->setSolverIterationCounts(settings.SolverIterations, settings.SolverVelocityIterations); actor->setSolverIterationCounts(settings.SolverIterations, settings.SolverVelocityIterations);
physx::PxRigidBodyExt::setMassAndUpdateInertia(*actor, m_RigidBody.Mass);
m_ActorInternal = actor; m_ActorInternal = actor;
} }
else
{
m_ActorInternal = physics.createRigidStatic(pxTransform);
}
// Add Collider
if (m_Entity.HasComponent<BoxColliderComponent>()) PhysicsWrappers::AddBoxCollider(*this); if (m_Entity.HasComponent<BoxColliderComponent>()) PhysicsWrappers::AddBoxCollider(*this);
if (m_Entity.HasComponent<SphereColliderComponent>()) PhysicsWrappers::AddSphereCollider(*this); if (m_Entity.HasComponent<SphereColliderComponent>()) PhysicsWrappers::AddSphereCollider(*this);
if (m_Entity.HasComponent<CapsuleColliderComponent>()) PhysicsWrappers::AddCapsuleCollider(*this); if (m_Entity.HasComponent<CapsuleColliderComponent>()) PhysicsWrappers::AddCapsuleCollider(*this);
if (m_Entity.HasComponent<MeshColliderComponent>()) PhysicsWrappers::AddMeshCollider(*this); if (m_Entity.HasComponent<MeshColliderComponent>()) PhysicsWrappers::AddMeshCollider(*this);
if (IsDynamic())
{
auto* dynamicActor = static_cast<physx::PxRigidDynamic*>(m_ActorInternal);
physx::PxRigidBodyExt::setMassAndUpdateInertia(*dynamicActor, m_RigidBody.Mass);
}
if (!PhysicsLayerManager::IsLayerValid(m_RigidBody.Layer)) if (!PhysicsLayerManager::IsLayerValid(m_RigidBody.Layer))
m_RigidBody.Layer = 0; m_RigidBody.Layer = 0;

View File

@ -49,6 +49,8 @@ namespace Prism
Entity& GetEntity() { return m_Entity; } Entity& GetEntity() { return m_Entity; }
glm::vec3 GetWorldScale() const { return m_WorldScale; }
private: private:
void Initialize(); void Initialize();
void Spawn() const; void Spawn() const;
@ -64,6 +66,8 @@ namespace Prism
physx::PxRigidActor* m_ActorInternal; physx::PxRigidActor* m_ActorInternal;
glm::vec3 m_WorldScale = glm::vec3(1.0f);
friend class Physics3D; friend class Physics3D;
friend class PhysicsWrappers; friend class PhysicsWrappers;

View File

@ -36,12 +36,12 @@ namespace Prism
physx::PxVec3 ToPhysXVector(const glm::vec3& vector) physx::PxVec3 ToPhysXVector(const glm::vec3& vector)
{ {
return *(physx::PxVec3*)&vector; return physx::PxVec3(vector.x, vector.y, vector.z);
} }
physx::PxVec4 ToPhysXVector(const glm::vec4& vector) physx::PxVec4 ToPhysXVector(const glm::vec4& vector)
{ {
return *(physx::PxVec4*)&vector; return physx::PxVec4(vector.x, vector.y, vector.z, vector.w);
} }
physx::PxQuat ToPhysXQuat(const glm::quat& quat) physx::PxQuat ToPhysXQuat(const glm::quat& quat)

View File

@ -184,16 +184,11 @@ namespace Prism
auto& collider = actor.m_Entity.GetComponent<BoxColliderComponent>(); auto& collider = actor.m_Entity.GetComponent<BoxColliderComponent>();
if (!collider.Material) if (!collider.Material)
collider.Material = Ref<PhysicsMaterial>::Create(0.6F, 0.6F, 0.0f); collider.Material = Ref<PhysicsMaterialAsset>::Create(0.6F, 0.6F, 0.0f);
const glm::vec3 scale = actor.m_Entity.Transform().Scale; glm::vec3 colliderSize = collider.Size * actor.GetWorldScale();
glm::vec3 colliderSize = collider.Size;
if (scale.x != 0.0f) colliderSize.x *= scale.x; const auto boxGeometry = physx::PxBoxGeometry(colliderSize.x, colliderSize.y, colliderSize.z);
if (scale.y != 0.0f) colliderSize.y *= scale.y;
if (scale.z != 0.0f) colliderSize.z *= scale.z;
const auto boxGeometry = physx::PxBoxGeometry(colliderSize.x / 2.0f, colliderSize.y / 2.0f, colliderSize.z / 2.0f);
const physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness); const physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness);
physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, boxGeometry, *material); physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, boxGeometry, *material);
@ -207,7 +202,7 @@ namespace Prism
{ {
auto& collider = actor.m_Entity.GetComponent<SphereColliderComponent>(); auto& collider = actor.m_Entity.GetComponent<SphereColliderComponent>();
if (!collider.Material) if (!collider.Material)
collider.Material = Ref<PhysicsMaterial>::Create(0.6F, 0.6F, 0.0f); collider.Material = Ref<PhysicsMaterialAsset>::Create(0.6F, 0.6F, 0.0f);
const glm::vec3 scale = actor.m_Entity.Transform().Scale; const glm::vec3 scale = actor.m_Entity.Transform().Scale;
float colliderRadius = collider.Radius; float colliderRadius = collider.Radius;
@ -227,7 +222,7 @@ namespace Prism
{ {
auto& collider = actor.m_Entity.GetComponent<CapsuleColliderComponent>(); auto& collider = actor.m_Entity.GetComponent<CapsuleColliderComponent>();
if (!collider.Material) if (!collider.Material)
collider.Material = Ref<PhysicsMaterial>::Create(0.6F, 0.6F, 0.0f); collider.Material = Ref<PhysicsMaterialAsset>::Create(0.6F, 0.6F, 0.0f);
const glm::vec3 scale = actor.m_Entity.Transform().Scale; const glm::vec3 scale = actor.m_Entity.Transform().Scale;
float colliderRadius = collider.Radius; float colliderRadius = collider.Radius;
@ -255,7 +250,7 @@ namespace Prism
{ {
auto& collider = actor.m_Entity.GetComponent<MeshColliderComponent>(); auto& collider = actor.m_Entity.GetComponent<MeshColliderComponent>();
if (!collider.Material) if (!collider.Material)
collider.Material = Ref<PhysicsMaterial>::Create(0.6f, 0.6f, 0.0f); collider.Material = Ref<PhysicsMaterialAsset>::Create(0.6f, 0.6f, 0.0f);
glm::vec3 scale = actor.m_Entity.Transform().Scale; glm::vec3 scale = actor.m_Entity.Transform().Scale;
physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness); physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness);

View File

@ -75,8 +75,8 @@ namespace Prism
{ {
glTexStorage2D(GL_TEXTURE_2D, 1, format, width, height); glTexStorage2D(GL_TEXTURE_2D, 1, format, width, height);
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(TextureTarget(multisampled), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} }
@ -230,4 +230,12 @@ namespace Prism
glBindTextureUnit(slot, instance->m_ColorAttachments[attachmentIndex]); glBindTextureUnit(slot, instance->m_ColorAttachments[attachmentIndex]);
}); });
} }
void OpenGLFrameBuffer::BindDepthTexture(uint32_t slot) const
{
Ref<const OpenGLFrameBuffer> instance = this;
Renderer::Submit([instance, slot]() {
glBindTextureUnit(slot, instance->m_DepthAttachment);
});
}
} }

View File

@ -21,6 +21,7 @@ namespace Prism
void Resize(uint32_t width, uint32_t height, bool forceReCreate) override; void Resize(uint32_t width, uint32_t height, bool forceReCreate) override;
void BindTexture(uint32_t attachmentIndex, uint32_t slot) const override; void BindTexture(uint32_t attachmentIndex, uint32_t slot) const override;
void BindDepthTexture(uint32_t slot = 0) const override;
uint32_t GetWidth() const override { return m_Specification.Width; } uint32_t GetWidth() const override { return m_Specification.Width; }
uint32_t GetHeight() const override { return m_Specification.Height; } uint32_t GetHeight() const override { return m_Specification.Height; }

View File

@ -15,8 +15,8 @@ namespace Prism
OpenGLRenderPass(const RenderPassSpecification& spec); OpenGLRenderPass(const RenderPassSpecification& spec);
virtual ~OpenGLRenderPass(); virtual ~OpenGLRenderPass();
virtual RenderPassSpecification& GetSpecification() override { return m_Spec; } RenderPassSpecification& GetSpecification() override { return m_Spec; }
virtual const RenderPassSpecification& GetSpecification() const override { return m_Spec; } const RenderPassSpecification& GetSpecification() const override { return m_Spec; }
private: private:
RenderPassSpecification m_Spec; RenderPassSpecification m_Spec;

View File

@ -157,10 +157,13 @@ namespace Prism
glClearColor(r, g, b, a); glClearColor(r, g, b, a);
} }
void RendererAPI::DrawIndexed(uint32_t count, PrimitiveType type, bool depthTest, bool faceCulling) void RendererAPI::DrawIndexed(const uint32_t count, const PrimitiveType type, const bool depthTest, const bool faceCulling)
{ {
if (!depthTest) if (!depthTest)
{
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
}
GLenum glPrimitiveType = 0; GLenum glPrimitiveType = 0;
switch (type) switch (type)
@ -181,7 +184,10 @@ namespace Prism
glDrawElements(glPrimitiveType, count, GL_UNSIGNED_INT, nullptr); glDrawElements(glPrimitiveType, count, GL_UNSIGNED_INT, nullptr);
if (!depthTest) if (!depthTest)
{
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
}
} }
void RendererAPI::SetLineThickness(const float thickness) void RendererAPI::SetLineThickness(const float thickness)

View File

@ -54,7 +54,7 @@ namespace Prism
// Texture2D // Texture2D
// ****************************************** // ******************************************
OpenGLTexture2D::OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, TextureWrap wrap) OpenGLTexture2D::OpenGLTexture2D(const TextureFormat format, const uint32_t width, const uint32_t height, const TextureWrap wrap)
: m_Format(format), m_Width(width), m_Height(height), m_Wrap(wrap) : m_Format(format), m_Width(width), m_Height(height), m_Wrap(wrap)
{ {
Ref<OpenGLTexture2D> instance = this; Ref<OpenGLTexture2D> instance = this;
@ -83,6 +83,53 @@ namespace Prism
m_ImageData.Allocate(width * height * GetBPP(m_Format)); m_ImageData.Allocate(width * height * GetBPP(m_Format));
} }
OpenGLTexture2D::OpenGLTexture2D(const TextureFormat format, const uint32_t width, const uint32_t height, const void* data, const TextureWrap wrap)
: m_Format(format), m_Width(width), m_Height(height), m_Wrap(wrap)
{
// 计算图像数据大小(假设是 RGBA8或根据格式动态计算
uint32_t bpp = GetBPP(format);
uint32_t dataSize = width * height * bpp;
// 保存一份数据到 CPU 缓冲区(供后续可能的读取)
if (data)
{
m_ImageData.Allocate(dataSize);
memcpy(m_ImageData.Data, data, dataSize);
}
else
{
m_ImageData.Allocate(dataSize);
memset(m_ImageData.Data, 0, dataSize); // 可选初始化为0
}
Ref<OpenGLTexture2D> instance = this;
Renderer::Submit([instance]() mutable {
glGenTextures(1, &instance->m_RendererID);
glBindTexture(GL_TEXTURE_2D, instance->m_RendererID);
// 设置纹理参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLint wrap = instance->m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
glTextureParameterf(instance->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
// 上传数据(如果已有数据则使用,否则传 nullptr 创建空纹理)
glTexImage2D(GL_TEXTURE_2D, 0,
SizedInternalFormat(instance->m_Format),
(GLint)instance->m_Width, (GLint)instance->m_Height, 0,
ImageFormat(instance->m_Format),
DataType(instance->m_Format),
instance->m_ImageData.Data); // 这里传入数据指针
// 如果需要生成 mipmap取消注释下一行
// glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
});
}
OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb) OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb)
: m_FilePath(path) : m_FilePath(path)
@ -186,7 +233,7 @@ namespace Prism
}); });
} }
void OpenGLTexture2D::SetData(const void* data, int count) void OpenGLTexture2D::SetData(const void* data, uint32_t count)
{ {
Lock(); Lock();

View File

@ -14,6 +14,7 @@ namespace Prism
{ {
public: public:
OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, TextureWrap wrap); OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, TextureWrap wrap);
OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, const void* data, TextureWrap wrap = TextureWrap::Clamp);
OpenGLTexture2D(const std::string& path, bool srgb); OpenGLTexture2D(const std::string& path, bool srgb);
virtual ~OpenGLTexture2D(); virtual ~OpenGLTexture2D();
@ -30,7 +31,7 @@ namespace Prism
virtual void Lock() override; virtual void Lock() override;
virtual void Unlock() override; virtual void Unlock() override;
virtual void SetData(const void* data, int count) override; virtual void SetData(const void* data, uint32_t count) override;
virtual void Resize(uint32_t width, uint32_t height) override; virtual void Resize(uint32_t width, uint32_t height) override;
virtual Buffer GetWriteableBuffer() override; virtual Buffer GetWriteableBuffer() override;

View File

@ -16,6 +16,7 @@
#include "Prism/Core/Application.h" #include "Prism/Core/Application.h"
#include "efsw/efsw.hpp" #include "efsw/efsw.hpp"
#include "Prism/Utilities/StringUtils.h"
namespace Prism namespace Prism
{ {
@ -30,20 +31,22 @@ namespace Prism
public: public:
void handleFileAction(efsw::WatchID watchid, void handleFileAction(efsw::WatchID watchid,
const std::string& dir, const std::string& dir,
const std::string& filename, const std::string& filepath,
efsw::Action action, efsw::Action action,
std::string oldFilename = "") override std::string oldFilepath = "") override
{ {
// 如果引擎自身操作设置了忽略标志,则跳过本次事件 // 如果引擎自身操作设置了忽略标志,则跳过本次事件
if (FileSystem::s_IgnoreNextChange.load()) if (FileSystem::s_IgnoreNextChange.load())
return; return;
std::filesystem::path fullPath = std::filesystem::path(dir) / filename; std::string fullPath = (std::filesystem::path(dir) / filepath).string();
fullPath = Utils::NormalizePath(fullPath);
FileSystemChangedEvent e; FileSystemChangedEvent e;
e.FilePath = fullPath.string(); e.FilePath = fullPath;
e.NewName = filename; e.NewName = Utils::GetFilename(filepath);
e.OldName = oldFilename; // efsw 在重命名时会提供旧文件名 e.OldName = Utils::GetFilename(oldFilepath); // efsw 在重命名时会提供旧文件名
e.IsDirectory = false; // 稍后根据实际情况判断 e.IsDirectory = false; // 稍后根据实际情况判断
// 判断是否为目录(可能抛出异常,使用 error_code 版本) // 判断是否为目录(可能抛出异常,使用 error_code 版本)
@ -161,6 +164,30 @@ namespace Prism
return result ? std::string(result) : std::string(); return result ? std::string(result) : std::string();
} }
void FileSystem::OpenInExplorer(const std::string& path)
{
const std::filesystem::path absPath = std::filesystem::absolute(path);
if (!std::filesystem::exists(absPath))
{
PM_CORE_WARN("Path does not exist: {}", path);
return;
}
std::string cmd;
if (std::filesystem::is_directory(absPath))
{
// 打开目录
cmd = absPath.string();
ShellExecuteA(nullptr, "open", "explorer.exe", cmd.c_str(), NULL, SW_SHOW);
}
else
{
// 打开并选中文件
cmd = "/select, \"" + absPath.string() + "\"";
ShellExecuteA(nullptr, "open", "explorer.exe", cmd.c_str(), NULL, SW_SHOW);
}
}
bool FileSystem::CreateFolder(const std::filesystem::path& filepath) bool FileSystem::CreateFolder(const std::filesystem::path& filepath)
{ {

View File

@ -62,7 +62,7 @@ namespace Prism
m_Data.VSync = enable; m_Data.VSync = enable;
} }
std::pair<float, float> WindowsWindow::GetWindowPos() const glm::vec2 WindowsWindow::GetWindowPos() const
{ {
int x, y; int x, y;
glfwGetWindowPos(m_Window, &x, &y); glfwGetWindowPos(m_Window, &x, &y);
@ -91,6 +91,8 @@ namespace Prism
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_DEPTH_BITS, 24);
s_GLFWInitialized = true; s_GLFWInitialized = true;
} }
@ -119,16 +121,37 @@ namespace Prism
glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window) glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window)
{ {
auto& data = *((WindowData*)glfwGetWindowUserPointer(window)); const auto& data = *((WindowData*)glfwGetWindowUserPointer(window));
WindowCloseEvent event; WindowCloseEvent event;
data.EventCallback(event); data.EventCallback(event);
}); });
glfwSetWindowFocusCallback(m_Window, [](GLFWwindow* window, const int focused) {
const auto& data = *((WindowData*)glfwGetWindowUserPointer(window));
if (focused)
{
WindowFocusEvent event;
data.EventCallback(event);
}
else
{
WindowLostFocusEvent event;
data.EventCallback(event);
}
});
glfwSetWindowPosCallback(m_Window, [](GLFWwindow* window, int xpos, int ypos) {
const auto& data = *((WindowData*)glfwGetWindowUserPointer(window));
WindowMovedEvent event(xpos, ypos);
data.EventCallback(event);
});
glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods) glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods)
{ {
auto& data = *((WindowData*)glfwGetWindowUserPointer(window)); const auto& data = *((WindowData*)glfwGetWindowUserPointer(window));
switch (action) switch (action)
{ {

View File

@ -27,8 +27,8 @@ namespace Prism
bool const IsVSync() const override { return m_Data.VSync; } bool const IsVSync() const override { return m_Data.VSync; }
void SetVSync(bool enable) override; void SetVSync(bool enable) override;
virtual std::pair<uint32_t, uint32_t> GetSize() const override { return { m_Data.Width, m_Data.Height }; } virtual glm::ivec2 GetSize() const override { return { m_Data.Width, m_Data.Height }; }
virtual std::pair<float, float> GetWindowPos() const override; virtual glm::vec2 GetWindowPos() const override;
virtual const std::string& GetTitle() const override { return m_Data.Title; } virtual const std::string& GetTitle() const override { return m_Data.Title; }
virtual void SetTitle(const std::string& title) override; virtual void SetTitle(const std::string& title) override;

View File

@ -78,6 +78,7 @@ namespace Prism
virtual void Resize(uint32_t width, uint32_t height, bool forceReCreate = false) = 0; virtual void Resize(uint32_t width, uint32_t height, bool forceReCreate = false) = 0;
virtual void BindTexture(uint32_t attachmentIndex = 0, uint32_t slot = 0) const = 0; virtual void BindTexture(uint32_t attachmentIndex = 0, uint32_t slot = 0) const = 0;
virtual void BindDepthTexture(uint32_t slot = 0) const = 0;
virtual uint32_t GetWidth() const = 0; virtual uint32_t GetWidth() const = 0;
virtual uint32_t GetHeight() const = 0; virtual uint32_t GetHeight() const = 0;

View File

@ -140,6 +140,27 @@ namespace Prism
return Ref<MaterialInstance>::Create(material); return Ref<MaterialInstance>::Create(material);
} }
Ref<MaterialInstance> MaterialInstance::Copy(Ref<MaterialInstance> other)
{
if (!other) return nullptr;
auto newInstance = Create(other->m_Material);
newInstance->m_Name = other->m_Name + "_Override";
// 复制 uniform 缓冲区
newInstance->m_VSUniformStorageBuffer = Buffer::Copy(other->m_VSUniformStorageBuffer.Data, other->m_VSUniformStorageBuffer.GetSize());
newInstance->m_PSUniformStorageBuffer = Buffer::Copy(other->m_PSUniformStorageBuffer.Data, other->m_PSUniformStorageBuffer.GetSize());
// 复制纹理列表(共享纹理引用)
newInstance->m_Textures = other->m_Textures;
// 复制覆盖标记集合
newInstance->m_OverriddenValues = other->m_OverriddenValues;
return newInstance;
}
void MaterialInstance::OnShaderReloaded() void MaterialInstance::OnShaderReloaded()
{ {
AllocateStorage(); AllocateStorage();

View File

@ -119,6 +119,11 @@ namespace Prism
static Ref<MaterialInstance> Create(const Ref<Material>& material); static Ref<MaterialInstance> Create(const Ref<Material>& material);
/**
*
* @param other copy other data to a new Data
* @return the new Data will as Ref return
*/
static Ref<MaterialInstance> Copy(Ref<MaterialInstance> other); static Ref<MaterialInstance> Copy(Ref<MaterialInstance> other);
template<typename T> template<typename T>

View File

@ -64,6 +64,13 @@ namespace Prism
return result; return result;
} }
static AABB UnionAABB(const AABB& a, const AABB& b) {
AABB result;
result.Min = glm::min(a.Min, b.Min);
result.Max = glm::max(a.Max, b.Max);
return result;
}
void AnimatedVertex::AddBoneData(uint32_t BoneID, float Weight) void AnimatedVertex::AddBoneData(uint32_t BoneID, float Weight)
{ {
@ -300,9 +307,9 @@ namespace Prism
std::string texturePath = parentPath.string(); std::string texturePath = parentPath.string();
PM_MESH_LOG(" Albedo map path = {0}", texturePath); PM_MESH_LOG(" Albedo map path = {0}", texturePath);
auto texture = AssetsManager::GetAsset<Texture2D>(texturePath); auto texture = AssetsManager::TryGetAsset<Texture2D>(texturePath);
// auto texture = Texture2D::Create(texturePath, true); // auto texture = Texture2D::Create(texturePath, true);
if (texture->Loaded()) if (texture && texture->Loaded())
{ {
m_Textures[i] = texture; m_Textures[i] = texture;
mi->Set("u_AlbedoTexture", m_Textures[i]); mi->Set("u_AlbedoTexture", m_Textures[i]);
@ -333,9 +340,9 @@ namespace Prism
std::string texturePath = parentPath.string(); std::string texturePath = parentPath.string();
PM_MESH_LOG(" Normal map path = {0}", texturePath); PM_MESH_LOG(" Normal map path = {0}", texturePath);
auto texture = AssetsManager::GetAsset<Texture2D>(texturePath); auto texture = AssetsManager::TryGetAsset<Texture2D>(texturePath);
// auto texture = Texture2D::Create(texturePath); // auto texture = Texture2D::Create(texturePath);
if (texture->Loaded()) if (texture && texture->Loaded())
{ {
mi->Set("u_NormalTexture", texture); mi->Set("u_NormalTexture", texture);
mi->Set("u_NormalTexToggle", 1.0f); mi->Set("u_NormalTexToggle", 1.0f);
@ -362,9 +369,9 @@ namespace Prism
std::string texturePath = parentPath.string(); std::string texturePath = parentPath.string();
PM_MESH_LOG(" Roughness map path = {0}", texturePath); PM_MESH_LOG(" Roughness map path = {0}", texturePath);
auto texture = AssetsManager::GetAsset<Texture2D>(texturePath); auto texture = AssetsManager::TryGetAsset<Texture2D>(texturePath);
// auto texture = Texture2D::Create(texturePath); // auto texture = Texture2D::Create(texturePath);
if (texture->Loaded()) if (texture && texture->Loaded())
{ {
PM_CORE_TRACE(" Roughness map path = {0}", texturePath); PM_CORE_TRACE(" Roughness map path = {0}", texturePath);
mi->Set("u_RoughnessTexture", texture); mi->Set("u_RoughnessTexture", texture);
@ -458,9 +465,9 @@ namespace Prism
PM_MESH_LOG(" Metalness map path = {0}", texturePath); PM_MESH_LOG(" Metalness map path = {0}", texturePath);
auto texture = AssetsManager::GetAsset<Texture2D>(texturePath); auto texture = AssetsManager::TryGetAsset<Texture2D>(texturePath);
// auto texture = Texture2D::Create(texturePath); // auto texture = Texture2D::Create(texturePath);
if (texture->Loaded()) if (texture && texture->Loaded())
{ {
mi->Set("u_MetalnessTexture", texture); mi->Set("u_MetalnessTexture", texture);
mi->Set("u_MetalnessTexToggle", 1.0f); mi->Set("u_MetalnessTexToggle", 1.0f);
@ -517,6 +524,32 @@ namespace Prism
PipelineSpecification pipelineSpecification; PipelineSpecification pipelineSpecification;
pipelineSpecification.Layout = vertexBufferLayout; pipelineSpecification.Layout = vertexBufferLayout;
m_Pipeline = Pipeline::Create(pipelineSpecification); m_Pipeline = Pipeline::Create(pipelineSpecification);
if (!m_IsAnimated)
{
for (const auto& submesh : m_Submeshes) {
glm::vec3 corners[8];
corners[0] = submesh.Transform * glm::vec4(submesh.BoundingBox.Min, 1.0f);
corners[1] = submesh.Transform * glm::vec4(submesh.BoundingBox.Max, 1.0f);
corners[2] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Min.x, submesh.BoundingBox.Min.y, submesh.BoundingBox.Max.z), 1.0f);
corners[3] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Min.x, submesh.BoundingBox.Max.y, submesh.BoundingBox.Min.z), 1.0f);
corners[4] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Min.x, submesh.BoundingBox.Max.y, submesh.BoundingBox.Max.z), 1.0f);
corners[5] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Max.x, submesh.BoundingBox.Min.y, submesh.BoundingBox.Min.z), 1.0f);
corners[6] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Max.x, submesh.BoundingBox.Min.y, submesh.BoundingBox.Max.z), 1.0f);
corners[7] = submesh.Transform * glm::vec4(glm::vec3(submesh.BoundingBox.Max.x, submesh.BoundingBox.Max.y, submesh.BoundingBox.Min.z), 1.0f);
AABB transformedAABB;
transformedAABB.Min = corners[0];
transformedAABB.Max = corners[0];
for (int i = 1; i < 8; ++i) {
transformedAABB.Min = glm::min(transformedAABB.Min, corners[i]);
transformedAABB.Max = glm::max(transformedAABB.Max, corners[i]);
}
m_BoundingBox = UnionAABB(m_BoundingBox, transformedAABB);
}
}
} }
Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<Index>& indices, const glm::mat4& transform) Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<Index>& indices, const glm::mat4& transform)
@ -541,6 +574,16 @@ namespace Prism
{ ShaderDataType::Float2, "a_TexCoord" }, { ShaderDataType::Float2, "a_TexCoord" },
}; };
m_Pipeline = Pipeline::Create(pipelineSpecification); m_Pipeline = Pipeline::Create(pipelineSpecification);
// boundingbox
m_BoundingBox.Min = glm::vec3(FLT_MAX);
m_BoundingBox.Max = glm::vec3(-FLT_MAX);
for (const auto& vertex : vertices) {
glm::vec3 transformedPos = transform * glm::vec4(vertex.Position, 1.0f);
m_BoundingBox.Min = glm::min(m_BoundingBox.Min, transformedPos);
m_BoundingBox.Max = glm::max(m_BoundingBox.Max, transformedPos);
}
} }
Mesh::~Mesh() = default; Mesh::~Mesh() = default;
@ -569,6 +612,24 @@ namespace Prism
*/ */
} }
void Mesh::TraverseNodes(const aiNode* node, const glm::mat4& parentTransform, uint32_t level)
{
const glm::mat4 localTransform = parentTransform * Mat4FromAssimpMat4(node->mTransformation);
glm::mat4 transform = parentTransform * localTransform;
for (uint32_t i = 0; i < node->mNumMeshes; i++)
{
const uint32_t mesh = node->mMeshes[i];
auto& submesh = m_Submeshes[mesh];
submesh.NodeName = node->mName.C_Str();
submesh.Transform = transform;
submesh.LocalTransform = localTransform;
}
for (uint32_t i = 0; i < node->mNumChildren; i++)
{
TraverseNodes(node->mChildren[i], localTransform, level + 1);
}
}
void Mesh::DumpVertexBuffer() void Mesh::DumpVertexBuffer()
{ {
@ -657,24 +718,6 @@ namespace Prism
} }
*/ */
void Mesh::TraverseNodes(const aiNode* node, const glm::mat4& parentTransform, uint32_t level)
{
const glm::mat4 localTransform = parentTransform * Mat4FromAssimpMat4(node->mTransformation);
glm::mat4 transform = parentTransform * localTransform;
for (uint32_t i = 0; i < node->mNumMeshes; i++)
{
const uint32_t mesh = node->mMeshes[i];
auto& submesh = m_Submeshes[mesh];
submesh.NodeName = node->mName.C_Str();
submesh.Transform = transform;
submesh.LocalTransform = localTransform;
}
for (uint32_t i = 0; i < node->mNumChildren; i++)
{
TraverseNodes(node->mChildren[i], localTransform, level + 1);
}
}
/* /*
const aiNodeAnim* Mesh::FindNodeAnim(const aiAnimation* animation, const std::string& nodeName) const aiNodeAnim* Mesh::FindNodeAnim(const aiAnimation* animation, const std::string& nodeName)

View File

@ -141,6 +141,9 @@ namespace Prism
{ {
return m_AnimatorController ? m_AnimatorController->GetFinalBoneTransforms() : m_EmptyTransforms; return m_AnimatorController ? m_AnimatorController->GetFinalBoneTransforms() : m_EmptyTransforms;
} }
const AABB& GetBoundingBox() const { return m_BoundingBox; }
private: private:
void TraverseNodes(const aiNode* node, const glm::mat4& parentTransform = glm::mat4(1.0f), uint32_t level = 0); void TraverseNodes(const aiNode* node, const glm::mat4& parentTransform = glm::mat4(1.0f), uint32_t level = 0);
@ -182,6 +185,9 @@ namespace Prism
// float m_TimeMultiplier = 1.0f; // float m_TimeMultiplier = 1.0f;
std::string m_FilePath; std::string m_FilePath;
AABB m_BoundingBox;
private: private:
friend class Renderer; friend class Renderer;
friend class SceneHierarchyPanel; friend class SceneHierarchyPanel;

View File

@ -42,8 +42,8 @@ namespace Prism
// FullScreen Quad // FullScreen Quad
static float fullScreenQuadVertex[] = { static float fullScreenQuadVertex[] = {
-1.0f, -1.0f, 0.1f, 0.0f, 0.0f, -1.0f, -1.0f, 0.1f, 0.0f, 0.0f,
1.0f, -1.0f, 0.1f, 1.0f, 0.0f, 1.0f, -1.0f, 0.1f, 1.0f, 0.0f,
1.0f, 1.0f, 0.1f, 1.0f, 1.0f, 1.0f, 1.0f, 0.1f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.1f, 0.0f, 1.0f -1.0f, 1.0f, 0.1f, 0.0f, 1.0f
}; };
static uint32_t fullScreenQuadIndices[] = { static uint32_t fullScreenQuadIndices[] = {
@ -66,7 +66,7 @@ namespace Prism
{ {
Submit([]() Submit([]()
{ {
RendererAPI::Clear(0.0f, 0.0f, 0.0f, 1.0f); RendererAPI::Clear(0.0f, 0.0f, 0.0f, 1.0f);
}); });
} }
@ -81,6 +81,13 @@ namespace Prism
{ {
} }
Ref<ShaderLibrary> Renderer::GetShaderLibrary()
{
return s_Data.m_ShaderLibrary;
}
void Renderer::DrawIndexed(const uint32_t count, const PrimitiveType type, const bool depthTest, bool cullFace) void Renderer::DrawIndexed(const uint32_t count, const PrimitiveType type, const bool depthTest, bool cullFace)
{ {
Submit([=]() { Submit([=]() {
@ -88,13 +95,6 @@ namespace Prism
}); });
} }
Ref<ShaderLibrary> Renderer::GetShaderLibrary()
{
return s_Data.m_ShaderLibrary;
}
void Renderer::SetLineThickness(const float thickness) void Renderer::SetLineThickness(const float thickness)
{ {
Submit([=]() { Submit([=]() {
@ -135,7 +135,7 @@ namespace Prism
void Renderer::SubmitQuad(Ref<MaterialInstance>& material, const glm::mat4& transform) void Renderer::SubmitQuad(Ref<MaterialInstance>& material, const glm::mat4& transform)
{ {
bool depthTest = true; bool depthTest = true;
bool cullFace = true; bool cullFace = true;
if (material) if (material)
{ {
@ -172,6 +172,55 @@ namespace Prism
Renderer::DrawIndexed(6, PrimitiveType::Triangles, depthTest, cullFace); Renderer::DrawIndexed(6, PrimitiveType::Triangles, depthTest, cullFace);
} }
void Renderer::SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials)
{
// auto material = overrideMaterial ? overrideMaterial : mesh->GetMaterialInstance();
// auto shader = material->GetShader();
// TODO: Sort this out
mesh->m_VertexBuffer->Bind();
mesh->m_Pipeline->Bind();
mesh->m_IndexBuffer->Bind();
const auto& materials = mesh->GetMaterials();
for (Submesh& submesh : mesh->m_Submeshes)
{
// Material
auto material = overrideMaterials.empty() ? materials[submesh.MaterialIndex] : overrideMaterials[submesh.MaterialIndex];
auto shader = material->GetShader();
material->Bind();
if (mesh->m_IsAnimated)
{
const auto& boneTransform = mesh->GetBoneTransforms();
for (size_t i = 0; i < boneTransform.size(); i++)
{
std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]");
shader->SetMat4(uniformName, boneTransform[i]);
}
}
shader->SetMat4("u_Transform", transform * submesh.Transform);
Renderer::Submit([submesh, material]() {
if (material->GetFlag(MaterialFlag::DepthTest))
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
}
else
glDisable(GL_DEPTH_TEST);
if (!material->GetFlag(MaterialFlag::TwoSided))
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex);
});
}
}
void Renderer::SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial) void Renderer::SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial)
{ {
// auto material = overrideMaterial ? overrideMaterial : mesh->GetMaterialInstance(); // auto material = overrideMaterial ? overrideMaterial : mesh->GetMaterialInstance();
@ -203,7 +252,10 @@ namespace Prism
Renderer::Submit([submesh, material]() { Renderer::Submit([submesh, material]() {
if (material->GetFlag(MaterialFlag::DepthTest)) if (material->GetFlag(MaterialFlag::DepthTest))
{
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
}
else else
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -243,32 +295,6 @@ namespace Prism
} }
} }
void Renderer::DrawAABB(const Ref<Mesh>& mesh, const glm::mat4& transform, const glm::vec4& color)
{
for (const Submesh& submesh : mesh->m_Submeshes)
{
const auto& aabb = submesh.BoundingBox;
auto aabbTransform = transform * submesh.Transform;
DrawAABB(aabb, aabbTransform, color);
}
}
void Renderer::DispatchCompute(int x, int y, int z)
{
Submit([x, y, z]()
{
RendererAPI::DispatchCompute(x, y, z);
});
}
void Renderer::MemoryBarrier(int barrier)
{
Submit([barrier]()
{
RendererAPI::MemoryBarrier(barrier);
});
}
void Renderer::DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color) void Renderer::DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color)
{ {
glm::vec4 min = { aabb.Min.x, aabb.Min.y, aabb.Min.z, 1.0f }; glm::vec4 min = { aabb.Min.x, aabb.Min.y, aabb.Min.z, 1.0f };
@ -297,6 +323,32 @@ namespace Prism
Renderer2D::DrawLine(corners[i], corners[i + 4], color); Renderer2D::DrawLine(corners[i], corners[i + 4], color);
} }
void Renderer::DrawAABB(const Ref<Mesh>& mesh, const glm::mat4& transform, const glm::vec4& color)
{
for (const Submesh& submesh : mesh->m_Submeshes)
{
const auto& aabb = submesh.BoundingBox;
auto aabbTransform = transform * submesh.Transform;
DrawAABB(aabb, aabbTransform, color);
}
}
void Renderer::DispatchCompute(int x, int y, int z)
{
Submit([x, y, z]()
{
RendererAPI::DispatchCompute(x, y, z);
});
}
void Renderer::MemoryBarrier(int barrier)
{
Submit([barrier]()
{
RendererAPI::MemoryBarrier(barrier);
});
}
RenderCommandQueue& Renderer::GetRenderCommandQueue() RenderCommandQueue& Renderer::GetRenderCommandQueue()
{ {
return s_Data.m_CommandQueue; return s_Data.m_CommandQueue;

View File

@ -54,7 +54,8 @@ namespace Prism
static void SubmitQuad(Ref<MaterialInstance>& material, const glm::mat4& transform = glm::mat4(1.0f)); static void SubmitQuad(Ref<MaterialInstance>& material, const glm::mat4& transform = glm::mat4(1.0f));
static void SubmitFullscreenQuad(Ref<MaterialInstance> material); static void SubmitFullscreenQuad(Ref<MaterialInstance> material);
static void SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial = nullptr); static void SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials = {});
static void SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial = nullptr);
static void SubmitMeshWithShader(Ref<Mesh> mesh, const glm::mat4& transform, Ref<Shader> shader); static void SubmitMeshWithShader(Ref<Mesh> mesh, const glm::mat4& transform, Ref<Shader> shader);
static void DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color = glm::vec4(1.0f)); static void DrawAABB(const AABB& aabb, const glm::mat4& transform, const glm::vec4& color = glm::vec4(1.0f));

View File

@ -25,28 +25,20 @@ namespace Prism
LightEnvironment SceneLightEnvironment; LightEnvironment SceneLightEnvironment;
// Resources // Resources
Ref<MaterialInstance> SkyboxMaterial;
Ref<Environment> SceneEnvironment; Ref<Environment> SceneEnvironment;
Ref<TextureCube> SkyboxTexture;
float SkyboxLoad;
} SceneData; } SceneData;
Ref<Texture2D> BRDFLUT; Ref<Texture2D> BRDFLUT;
Ref<Shader> CompositeShader; Ref<Shader> CompositeShader;
Ref<Shader> BloomBlurShader; Ref<Shader> BloomBlurShader;
// Ref<Shader> BloomBlendShader; Ref<Shader> BloomBlendShader;
Ref<RenderPass> GeoPass; Ref<RenderPass> GeoPass;
Ref<RenderPass> LightingPass;
Ref<Shader> LightingShader;
// Ref<RenderPass> CompositePass; // Ref<RenderPass> CompositePass;
Ref<RenderPass> BloomBlurPass[2]; Ref<RenderPass> BloomBlurPass[2];
Ref<RenderPass> BloomBlendPass; Ref<RenderPass> BloomBlendPass;
Ref<Texture2D> ResolvedHDRTexture; // 解析后的单样本 HDR 颜色 Ref<Texture2D> ResolvedHDRTexture; // 解析后的单样本 HDR 颜色
int Quality = 6;
float Directions = 32.0f;
float Size = 16.0f;
struct AutoExposureData struct AutoExposureData
{ {
@ -57,7 +49,7 @@ namespace Prism
bool EnableAutoExposure = true; bool EnableAutoExposure = true;
float Key = 0.3f; float Key = 0.3f;
Timer ExposureTimer; Timer ExposureTimer;
float MaxExposure = 5.0f; float MaxExposure = 1.5f;
float MinExposure = 0.01f; float MinExposure = 0.01f;
// 直方图模式参数 // 直方图模式参数
@ -103,12 +95,12 @@ namespace Prism
bool ShadowEnabled = true; bool ShadowEnabled = true;
float ShadowBias = 0.001f; float ShadowBias = 0.001f;
float ShadowIntensity = 0.0f; float ShadowIntensity = 0.0f;
float ShadowSoftness = 0.0f; int ShadowSoftness = 0;
struct DrawCommand struct DrawCommand
{ {
Ref<Mesh> mesh; Ref<Mesh> mesh;
Ref<MaterialInstance> Material; std::vector<Ref<MaterialInstance>> MaterialInstances;
glm::mat4 Transform; glm::mat4 Transform;
}; };
std::vector<DrawCommand> DrawList; std::vector<DrawCommand> DrawList;
@ -136,21 +128,18 @@ namespace Prism
SceneRendererOptions Options; SceneRendererOptions Options;
Ref<TextureCube> BlackCubeTexture; Ref<TextureCube> BlackCubeTexture;
Ref<Texture2D> BlackTexture;
}; };
struct Renderer3DStats struct Renderer3DStats
{ {
float ShadowPass = 0.0f; float ShadowPass = 0.0f;
float GeometryPass = 0.0f; float GeometryPass = 0.0f;
float LightingPass = 0.0f;
float BloomPass = 0.0f;
float CompositePass = 0.0f; float CompositePass = 0.0f;
float AutoExposurePass = 0.0f; float AutoExposurePass = 0.0f;
Timer ShadowPassTimer; Timer ShadowPassTimer;
Timer GeometryPassTimer; Timer GeometryPassTimer;
Timer LightingPassTimer;
Timer BloomPassTimer;
Timer CompositePassTimer; Timer CompositePassTimer;
Timer AutoExposurePassTimer; Timer AutoExposurePassTimer;
}; };
@ -165,15 +154,9 @@ namespace Prism
//////////////// GeoPass //////////////// //////////////// GeoPass ////////////////
{ {
FramebufferSpecification geoFramebufferSpec; FramebufferSpecification geoFramebufferSpec;
geoFramebufferSpec.Attachments = { geoFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA32F, FramebufferTextureFormat::DEPTH24STENCIL8 };
FramebufferTextureFormat::RGBA16F, // Albedo + Metallic geoFramebufferSpec.Samples = 8;
FramebufferTextureFormat::RGBA16F, // Normal + Roughness geoFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
FramebufferTextureFormat::RGBA16F, // Emissive+AO
FramebufferTextureFormat::DEPTH24STENCIL8 // Depth
};
geoFramebufferSpec.Samples = 1;
geoFramebufferSpec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
RenderPassSpecification geoRenderPassSpec; RenderPassSpecification geoRenderPassSpec;
geoRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(geoFramebufferSpec); geoRenderPassSpec.TargetFramebuffer = FrameBuffer::Create(geoFramebufferSpec);
@ -182,18 +165,6 @@ namespace Prism
///////////////////////////////////////////// /////////////////////////////////////////////
//////////////// GeoPass ////////////////
FramebufferSpecification spec;
spec.Attachments = { FramebufferTextureFormat::RGBA16F }; // HDR 颜色输出
spec.Samples = 1;
spec.ClearColor = { 0.0f, 0.0f, 0.0f, 0.0f };
RenderPassSpecification rpSpec;
rpSpec.TargetFramebuffer = FrameBuffer::Create(spec);
s_Data.LightingPass = RenderPass::Create(rpSpec);
s_Data.LightingShader = Shader::Create("assets/shaders/Lighting.glsl");
/////////////////////////////////////////////
//////////////// BloomPass //////////////// //////////////// BloomPass ////////////////
{ {
FramebufferSpecification bloomBlurFramebufferSpec; FramebufferSpecification bloomBlurFramebufferSpec;
@ -215,7 +186,7 @@ namespace Prism
s_Data.BloomBlendPass = RenderPass::Create(bloomBlendRenderPassSpec); s_Data.BloomBlendPass = RenderPass::Create(bloomBlendRenderPassSpec);
s_Data.BloomBlurShader = Shader::Create("assets/shaders/BloomBlur.glsl"); s_Data.BloomBlurShader = Shader::Create("assets/shaders/BloomBlur.glsl");
// s_Data.BloomBlendShader = Shader::Create("assets/shaders/BloomBlend.glsl"); s_Data.BloomBlendShader = Shader::Create("assets/shaders/BloomBlend.glsl");
} }
///////////////////////////////////////////// /////////////////////////////////////////////
@ -297,6 +268,7 @@ namespace Prism
uint32_t blackTextureData[6] = { 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000 }; uint32_t blackTextureData[6] = { 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000 };
s_Data.BlackCubeTexture = TextureCube::Create(TextureFormat::RGBA, 1, 1, &blackTextureData); s_Data.BlackCubeTexture = TextureCube::Create(TextureFormat::RGBA, 1, 1, &blackTextureData);
s_Data.BlackTexture = Texture2D::Create(TextureFormat::RGBA, 1, 1, &blackTextureData[0]);
} }
void Renderer3D::SetViewportSize(const uint32_t width, const uint32_t height) void Renderer3D::SetViewportSize(const uint32_t width, const uint32_t height)
@ -314,8 +286,7 @@ namespace Prism
void Renderer3D::BeginScene(const Scene* scene, const SceneRendererCamera& camera) void Renderer3D::BeginScene(const Scene* scene, const SceneRendererCamera& camera)
{ {
s_Data.SceneData.SceneCamera = camera; s_Data.SceneData.SceneCamera = camera;
s_Data.SceneData.SkyboxTexture = scene->m_SkyboxTexture; s_Data.SceneData.SkyboxMaterial = scene->m_SkyboxMaterial;
s_Data.SceneData.SkyboxLoad = scene->m_SkyboxLod;
s_Data.SceneData.SceneEnvironment = scene->m_Environment; s_Data.SceneData.SceneEnvironment = scene->m_Environment;
s_Data.SceneData.SceneEnvironmentIntensity = scene->m_EnvironmentIntensity; s_Data.SceneData.SceneEnvironmentIntensity = scene->m_EnvironmentIntensity;
s_Data.SceneData.SceneLightEnvironment = scene->m_LightEnvironment; s_Data.SceneData.SceneLightEnvironment = scene->m_LightEnvironment;
@ -326,39 +297,39 @@ namespace Prism
FlushDrawList(renderPass); FlushDrawList(renderPass);
} }
void Renderer3D::SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial) void Renderer3D::SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials)
{ {
// TODO: Culling, sorting, etc. // TODO: Culling, sorting, etc.
s_Data.DrawList.push_back({ mesh, overrideMaterial, transform }); s_Data.DrawList.push_back({ mesh, overrideMaterials, transform });
s_Data.ShadowPassDrawList.push_back({ mesh, overrideMaterial, transform }); s_Data.ShadowPassDrawList.push_back({ mesh, overrideMaterials, transform });
} }
void Renderer3D::SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform) void Renderer3D::SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials)
{ {
s_Data.SelectedMeshDrawList.push_back({ mesh, nullptr, transform }); s_Data.SelectedMeshDrawList.push_back({ mesh, overrideMaterials, transform });
s_Data.ShadowPassDrawList.push_back({ mesh, nullptr, transform }); s_Data.ShadowPassDrawList.push_back({ mesh, overrideMaterials, transform });
} }
void Renderer3D::SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform) void Renderer3D::SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform)
{ {
s_Data.ColliderDrawList.push_back({ component.DebugMesh, nullptr, glm::translate(parentTransform, component.Offset)}); s_Data.ColliderDrawList.push_back({ component.DebugMesh, {}, glm::translate(parentTransform, component.Offset)});
} }
void Renderer3D::SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform) void Renderer3D::SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform)
{ {
s_Data.ColliderDrawList.push_back({ component.DebugMesh, nullptr, parentTransform }); s_Data.ColliderDrawList.push_back({ component.DebugMesh, {}, parentTransform });
} }
void Renderer3D::SubmitColliderMesh(const CapsuleColliderComponent& component, const glm::mat4& parentTransform) void Renderer3D::SubmitColliderMesh(const CapsuleColliderComponent& component, const glm::mat4& parentTransform)
{ {
s_Data.ColliderDrawList.push_back({ component.DebugMesh, nullptr, parentTransform }); s_Data.ColliderDrawList.push_back({ component.DebugMesh, {}, parentTransform });
} }
void Renderer3D::SubmitColliderMesh(const MeshColliderComponent& component, const glm::mat4& parentTransform) void Renderer3D::SubmitColliderMesh(const MeshColliderComponent& component, const glm::mat4& parentTransform)
{ {
for (const auto debugMesh : component.ProcessedMeshes) for (const auto& debugMesh : component.ProcessedMeshes)
s_Data.ColliderDrawList.push_back({ debugMesh, nullptr, parentTransform }); s_Data.ColliderDrawList.push_back({ debugMesh, {}, parentTransform });
} }
// TODO: temp // TODO: temp
@ -482,6 +453,11 @@ namespace Prism
return s_Data.BlackCubeTexture; return s_Data.BlackCubeTexture;
} }
Ref<Texture2D> Renderer3D::GetBlackTexture()
{
return s_Data.BlackTexture;
}
void Renderer3D::FlushDrawList(Ref<RenderPass>& outRenderPass) void Renderer3D::FlushDrawList(Ref<RenderPass>& outRenderPass)
{ {
@ -499,34 +475,22 @@ namespace Prism
Renderer::Submit([] { s_Stats.GeometryPass = s_Stats.GeometryPassTimer.ElapsedMillis(); }); Renderer::Submit([] { s_Stats.GeometryPass = s_Stats.GeometryPassTimer.ElapsedMillis(); });
} }
{
Renderer::Submit([]() { s_Stats.LightingPassTimer.Reset(); });
LightingPass();
Renderer::Submit([] { s_Stats.LightingPass = s_Stats.LightingPassTimer.ElapsedMillis(); });
}
// ResolveMSAA();
// Compute average luminance and update exposure (GPU-copy + mipmap -> read 1 texel)
{ {
Renderer::Submit([]() { s_Stats.AutoExposurePassTimer.Reset(); }); Renderer::Submit([]() { s_Stats.AutoExposurePassTimer.Reset(); });
AutoExposurePass(); AutoExposurePass();
Renderer::Submit([] { s_Stats.AutoExposurePass = s_Stats.AutoExposurePassTimer.ElapsedMillis(); }); Renderer::Submit([] { s_Stats.AutoExposurePass = s_Stats.AutoExposurePassTimer.ElapsedMillis(); });
} }
{ ResolveMSAA();
Renderer::Submit([]() { s_Stats.BloomPassTimer.Reset(); });
BloomBlurPass();
Renderer::Submit([] { s_Stats.BloomPass = s_Stats.BloomPassTimer.ElapsedMillis(); });
}
BloomBlurPass();
GridPass();
{ {
Renderer::Submit([]() { s_Stats.CompositePassTimer.Reset(); }); Renderer::Submit([]() { s_Stats.CompositePassTimer.Reset(); });
CompositePass(outRenderPass); CompositePass(outRenderPass);
OverlayPass(outRenderPass);
Renderer::Submit([] { s_Stats.CompositePass = s_Stats.CompositePassTimer.ElapsedMillis(); }); Renderer::Submit([] { s_Stats.CompositePass = s_Stats.CompositePassTimer.ElapsedMillis(); });
// BloomBlurPass();
} }
s_Data.DrawList.clear(); s_Data.DrawList.clear();
@ -542,8 +506,7 @@ namespace Prism
if (!ae.EnableAutoExposure) if (!ae.EnableAutoExposure)
return; return;
auto srcFB = s_Data.LightingPass->GetSpecification().TargetFramebuffer; auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
// auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
auto dstFB = ae.LuminancePass->GetSpecification().TargetFramebuffer; auto dstFB = ae.LuminancePass->GetSpecification().TargetFramebuffer;
if (!srcFB || !dstFB) return; if (!srcFB || !dstFB) return;
@ -681,36 +644,22 @@ namespace Prism
const glm::vec3 cameraPosition = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3]; // TODO: Negate instead const glm::vec3 cameraPosition = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3]; // TODO: Negate instead
// Render entities // Skybox
Renderer::Submit([]() s_Data.SceneData.SkyboxMaterial->Set("u_InverseVP", glm::inverse(cameraViewProjection));
{ s_Data.SceneData.SkyboxMaterial->Set("u_SkyIntensity", s_Data.SceneData.SceneEnvironmentIntensity);
glEnable(GL_DEPTH_TEST); // s_Data.SceneInfo.EnvironmentIrradianceMap->Bind(0);
glDisable(GL_BLEND); Renderer::SubmitFullscreenQuad(s_Data.SceneData.SkyboxMaterial);
});
// const float aspectRatio = (float)s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetWidth() / (float)s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetHeight();
// float frustumSize = 2.0f * sceneCamera.Near * glm::tan(sceneCamera.FOV * 0.5f) * aspectRatio;
// Render entities
for (auto& dc : s_Data.DrawList) for (auto& dc : s_Data.DrawList)
{ {
auto baseMaterial = dc.mesh->GetMaterial(); auto baseMaterial = dc.mesh->GetMaterial();
baseMaterial->Set("u_GBufferMode", true);
baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection); baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection);
baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix); baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix);
baseMaterial->Set("u_CameraPosition", cameraPosition); baseMaterial->Set("u_CameraPosition", cameraPosition);
baseMaterial->Set("u_EmissiveColor", 1.0f);
baseMaterial->Set("u_EmissiveIntensity", 0.0f);
baseMaterial->Set("u_EmissiveTexToggle", 0.0f);
// baseMaterial->Set("u_LightMatrixCascade0", s_Data.LightMatrices[0]);
// baseMaterial->Set("u_LightMatrixCascade1", s_Data.LightMatrices[1]);
// baseMaterial->Set("u_LightMatrixCascade2", s_Data.LightMatrices[2]);
// baseMaterial->Set("u_LightMatrixCascade3", s_Data.LightMatrices[3]);
// baseMaterial->Set("u_ShowCascades", s_Data.ShowCascades);
// baseMaterial->Set("u_LightView", s_Data.LightViewMatrix);
// baseMaterial->Set("u_CascadeSplits", s_Data.CascadeSplits);
// baseMaterial->Set("u_SoftShadows", s_Data.SoftShadows);
// baseMaterial->Set("u_LightSize", s_Data.LightSize);
// baseMaterial->Set("u_MaxShadowDistance", s_Data.MaxShadowDistance);
// baseMaterial->Set("u_ShadowFade", s_Data.ShadowFade);
// baseMaterial->Set("u_CascadeFading", s_Data.CascadeFading);
// baseMaterial->Set("u_CascadeTransitionFade", s_Data.CascadeTransitionFade);
baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity); baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity);
// Environment (TODO: don't do this per mesh) // Environment (TODO: don't do this per mesh)
@ -747,38 +696,7 @@ namespace Prism
}); });
} }
/* Renderer::SubmitMesh(dc.mesh, dc.Transform, dc.MaterialInstances);
auto rd = baseMaterial->FindResourceDeclaration("u_ShadowMapTexture");
if (rd)
{
auto reg = rd->GetRegister();
auto tex = s_Data.ShadowMapRenderPass[0]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
auto tex1 = s_Data.ShadowMapRenderPass[1]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
auto tex2 = s_Data.ShadowMapRenderPass[2]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
auto tex3 = s_Data.ShadowMapRenderPass[3]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
Renderer::Submit([reg, tex, tex1, tex2, tex3]() mutable
{
// 4 cascades
glBindTextureUnit(reg, tex);
glBindSampler(reg++, s_Data.ShadowMapSampler);
glBindTextureUnit(reg, tex1);
glBindSampler(reg++, s_Data.ShadowMapSampler);
glBindTextureUnit(reg, tex2);
glBindSampler(reg++, s_Data.ShadowMapSampler);
glBindTextureUnit(reg, tex3);
glBindSampler(reg++, s_Data.ShadowMapSampler);
});
}
*/
constexpr auto overrideMaterial = nullptr; // dc.Material;
Renderer::SubmitMesh(dc.mesh, dc.Transform, overrideMaterial);
} }
if (outline) if (outline)
@ -795,17 +713,6 @@ namespace Prism
baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection); baseMaterial->Set("u_ViewProjectionMatrix", cameraViewProjection);
baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix); baseMaterial->Set("u_ViewMatrix", sceneCamera.ViewMatrix);
baseMaterial->Set("u_CameraPosition", cameraPosition); baseMaterial->Set("u_CameraPosition", cameraPosition);
baseMaterial->Set("u_EmissiveColor", 1.0f);
baseMaterial->Set("u_EmissiveIntensity", 0.0f);
baseMaterial->Set("u_EmissiveTexToggle", 0.0f);
// baseMaterial->Set("u_CascadeSplits", s_Data.CascadeSplits);
// baseMaterial->Set("u_ShowCascades", s_Data.ShowCascades);
// baseMaterial->Set("u_SoftShadows", s_Data.SoftShadows);
// baseMaterial->Set("u_LightSize", s_Data.LightSize);
// baseMaterial->Set("u_MaxShadowDistance", s_Data.MaxShadowDistance);
// baseMaterial->Set("u_ShadowFade", s_Data.ShadowFade);
// baseMaterial->Set("u_CascadeFading", s_Data.CascadeFading);
// baseMaterial->Set("u_CascadeTransitionFade", s_Data.CascadeTransitionFade);
baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity); baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity);
@ -814,11 +721,6 @@ namespace Prism
baseMaterial->Set("u_EnvIrradianceTex", s_Data.SceneData.SceneEnvironment->IrradianceMap); baseMaterial->Set("u_EnvIrradianceTex", s_Data.SceneData.SceneEnvironment->IrradianceMap);
baseMaterial->Set("u_BRDFLUTTexture", s_Data.BRDFLUT); baseMaterial->Set("u_BRDFLUTTexture", s_Data.BRDFLUT);
// baseMaterial->Set("u_LightMatrixCascade0", s_Data.LightMatrices[0]);
// baseMaterial->Set("u_LightMatrixCascade1", s_Data.LightMatrices[1]);
// baseMaterial->Set("u_LightMatrixCascade2", s_Data.LightMatrices[2]);
// baseMaterial->Set("u_LightMatrixCascade3", s_Data.LightMatrices[3]);
// Set lights (TODO: move to light environment and don't do per mesh) // Set lights (TODO: move to light environment and don't do per mesh)
baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.SceneLightEnvironment.DirectionalLights[0]); baseMaterial->Set("u_DirectionalLights", s_Data.SceneData.SceneLightEnvironment.DirectionalLights[0]);
baseMaterial->Set("u_PointLightCount", s_Data.SceneData.SceneLightEnvironment.PointLightCount); baseMaterial->Set("u_PointLightCount", s_Data.SceneData.SceneLightEnvironment.PointLightCount);
@ -847,37 +749,8 @@ namespace Prism
glBindSampler(reg, s_Data.ShadowMapSampler); glBindSampler(reg, s_Data.ShadowMapSampler);
}); });
} }
/*
auto rd = baseMaterial->FindResourceDeclaration("u_ShadowMapTexture");
if (rd)
{
auto reg = rd->GetRegister();
auto tex = s_Data.ShadowMapRenderPass[0]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); Renderer::SubmitMesh(dc.mesh, dc.Transform, dc.MaterialInstances);
auto tex1 = s_Data.ShadowMapRenderPass[1]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
auto tex2 = s_Data.ShadowMapRenderPass[2]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
auto tex3 = s_Data.ShadowMapRenderPass[3]->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
Renderer::Submit([reg, tex, tex1, tex2, tex3]() mutable
{
// 4 cascades
glBindTextureUnit(reg, tex);
glBindSampler(reg++, s_Data.ShadowMapSampler);
glBindTextureUnit(reg, tex1);
glBindSampler(reg++, s_Data.ShadowMapSampler);
glBindTextureUnit(reg, tex2);
glBindSampler(reg++, s_Data.ShadowMapSampler);
glBindTextureUnit(reg, tex3);
glBindSampler(reg++, s_Data.ShadowMapSampler);
});
}
*/
constexpr auto overrideMaterial = nullptr; // dc.Material;
Renderer::SubmitMesh(dc.mesh, dc.Transform, overrideMaterial);
} }
@ -927,9 +800,6 @@ namespace Prism
{ {
Renderer::Submit([]() Renderer::Submit([]()
{ {
// glStencilFunc(GL_NOTEQUAL, 1, 0xff);
// glStencilMask(0);
glLineWidth(1); glLineWidth(1);
glEnable(GL_LINE_SMOOTH); glEnable(GL_LINE_SMOOTH);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@ -958,14 +828,15 @@ namespace Prism
Renderer::Submit([]() Renderer::Submit([]()
{ {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// glStencilMask(0xff);
// glStencilFunc(GL_ALWAYS, 1, 0xff);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
}); });
} }
if (const auto option = GetOptions(); option.ShowBoundingBoxes) // Grid
const auto option = GetOptions();
if (option.ShowBoundingBoxes)
{ {
Renderer2D::BeginScene(cameraViewProjection); Renderer2D::BeginScene(cameraViewProjection);
for (auto& dc : s_Data.DrawList) for (auto& dc : s_Data.DrawList)
@ -976,112 +847,6 @@ namespace Prism
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
void Renderer3D::LightingPass()
{
Renderer::BeginRenderPass(s_Data.LightingPass);
s_Data.LightingShader->Bind();
// uniform
const glm::mat4 invViewProj = glm::inverse(s_Data.SceneData.SceneCamera.Camera.GetProjectionMatrix() * s_Data.SceneData.SceneCamera.ViewMatrix);
s_Data.LightingShader->SetMat4("u_InvViewProj", invViewProj);
const glm::vec3 cameraPosition = glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix)[3];
s_Data.LightingShader->SetFloat3("u_CameraPosition", cameraPosition);
// G-buffer
auto fb = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
Renderer::Submit([fb]() {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fb->GetColorAttachmentRendererID(0)); // AlbedoMetallic
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, fb->GetColorAttachmentRendererID(1)); // NormalRoughness
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, fb->GetColorAttachmentRendererID(2)); // EmissiveAO
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, fb->GetDepthAttachmentRendererID()); // Depth
});
s_Data.LightingShader->SetInt("u_AlbedoMetallic", 0);
s_Data.LightingShader->SetInt("u_NormalRoughness", 1);
s_Data.LightingShader->SetInt("u_EmissiveAO", 2);
s_Data.LightingShader->SetInt("u_Depth", 3);
// uniform
const auto& lights = s_Data.SceneData.SceneLightEnvironment;
// s_Data.LightingShader->SetStruct("u_DirectionalLights", lights.DirectionalLights[0]); // 需确保 SetStruct 支持
s_Data.LightingShader->SetFloat3("u_DirectionalLights.Direction", lights.DirectionalLights[0].Direction);
s_Data.LightingShader->SetFloat3("u_DirectionalLights.Radiance", lights.DirectionalLights[0].Radiance);
s_Data.LightingShader->SetFloat("u_DirectionalLights.Intensity", lights.DirectionalLights[0].Intensity);
s_Data.LightingShader->SetBool("u_DirectionalLights.CastShadows", lights.DirectionalLights[0].CastShadows);
s_Data.LightingShader->SetInt("u_PointLightCount", lights.PointLightCount);
// s_Data.LightingShader->SetStructArray("u_PointLights", lights.PointLights, lights.PointLightCount);
for (int i = 0; i < lights.PointLightCount; i++) {
std::string base = "u_PointLights[" + std::to_string(i) + "]";
s_Data.LightingShader->SetFloat3(base + ".Position", lights.PointLights[i].Position);
s_Data.LightingShader->SetFloat3(base + ".Radiance", lights.PointLights[i].Radiance);
s_Data.LightingShader->SetFloat(base + ".Intensity", lights.PointLights[i].Intensity);
s_Data.LightingShader->SetFloat(base + ".Range", lights.PointLights[i].Radius);
s_Data.LightingShader->SetBool(base + ".CastShadows", lights.PointLights[i].CastShadows);
}
s_Data.LightingShader->SetInt("u_SpotLightCount", lights.SpotLightCount);
for (int i = 0; i < lights.SpotLightCount; i++) {
std::string base = "u_SpotLights[" + std::to_string(i) + "]";
s_Data.LightingShader->SetFloat3(base + ".Position", lights.SpotLights[i].Position);
s_Data.LightingShader->SetFloat3(base + ".Direction", lights.SpotLights[i].Direction);
s_Data.LightingShader->SetFloat3(base + ".Radiance", lights.SpotLights[i].Radiance);
s_Data.LightingShader->SetFloat(base + ".Intensity", lights.SpotLights[i].Intensity);
s_Data.LightingShader->SetFloat(base + ".Range", lights.SpotLights[i].Range);
s_Data.LightingShader->SetFloat(base + ".InnerConeCos", lights.SpotLights[i].InnerConeCos);
s_Data.LightingShader->SetFloat(base + ".OuterConeCos", lights.SpotLights[i].OuterConeCos);
s_Data.LightingShader->SetBool(base + ".CastShadows", lights.SpotLights[i].CastShadows);
}
// IBL
s_Data.LightingShader->SetInt("u_EnvRadianceTex", 4);
s_Data.LightingShader->SetInt("u_EnvIrradianceTex", 5);
s_Data.LightingShader->SetInt("u_BRDFLUTTexture", 6);
s_Data.LightingShader->SetFloat("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity);
s_Data.LightingShader->SetFloat("u_EnvMapRotation", 0.0f); // 若需要可调整
const auto& sceneEnvironment = s_Data.SceneData.SceneEnvironment;
const auto& BRDFLUT = s_Data.BRDFLUT;
Renderer::Submit([sceneEnvironment, BRDFLUT]() {
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_CUBE_MAP, sceneEnvironment->RadianceMap->GetRendererID());
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_CUBE_MAP, sceneEnvironment->IrradianceMap->GetRendererID());
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, BRDFLUT->GetRendererID());
});
s_Data.LightingShader->SetMat4("u_LightSpaceMatrix", s_Data.LightMatrices);
s_Data.LightingShader->SetBool("u_ShadowEnabled", s_Data.ShadowEnabled);
s_Data.LightingShader->SetFloat("u_ShadowBias", s_Data.ShadowBias);
s_Data.LightingShader->SetFloat("u_ShadowIntensity", s_Data.ShadowIntensity);
s_Data.LightingShader->SetFloat("u_ShadowSoftness", s_Data.ShadowSoftness);
if (s_Data.ShadowEnabled) {
s_Data.LightingShader->SetInt("u_ShadowMap", 7);
Renderer::Submit([]() {
glActiveTexture(GL_TEXTURE7);
glBindTexture(GL_TEXTURE_2D, s_Data.ShadowMapRenderPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID());
glBindSampler(7, s_Data.ShadowMapSampler);
});
}
if (s_Data.SceneData.SkyboxTexture) {
s_Data.LightingShader->SetFloat("u_SkyTextureLod", s_Data.SceneData.SkyboxLoad);
s_Data.SceneData.SkyboxTexture->Bind(8);
s_Data.LightingShader->SetInt("u_Skybox", 8); // 使用纹理单元 8确保不与其他单元冲突
s_Data.LightingShader->SetFloat("u_SkyIntensity", s_Data.SceneData.SceneEnvironmentIntensity);
}
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
void Renderer3D::BloomBlurPass() void Renderer3D::BloomBlurPass()
{ {
if (!s_Data.EnableBloom) if (!s_Data.EnableBloom)
@ -1092,76 +857,62 @@ namespace Prism
return; return;
} }
// uint32_t srcTex = s_Data.ResolvedHDRTexture->GetRendererID(); const int iterations = 5; // 模糊迭代次数,可调
uint32_t srcTex = s_Data.LightingPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
// 第一次:提取高光 + 水平模糊 // 第一次:提取高光 + 水平模糊
{ {
Renderer::BeginRenderPass(s_Data.BloomBlurPass[0]); Renderer::BeginRenderPass(s_Data.BloomBlurPass[0]);
s_Data.BloomBlurShader->Bind(); s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0); s_Data.BloomBlurShader->SetInt("u_Texture", 0);
s_Data.BloomBlurShader->SetBool("u_FirstPass", true); s_Data.BloomBlurShader->SetBool("u_FirstPass", true);
s_Data.BloomBlurShader->SetFloat("u_Threshold", s_Data.BloomThreshold); s_Data.BloomBlurShader->SetFloat("u_Threshold", s_Data.BloomThreshold);
s_Data.BloomBlurShader->SetInt("u_Quality", s_Data.Quality); s_Data.ResolvedHDRTexture->Bind();
s_Data.BloomBlurShader->SetFloat("u_Directions", s_Data.Directions);
s_Data.BloomBlurShader->SetFloat("u_Size", s_Data.Size);
Renderer::Submit([srcTex]() { glBindTextureUnit(0, srcTex); });
Renderer::SubmitFullscreenQuad(nullptr); Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
uint32_t finalBlurTex = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID(); // 后续迭代
for (int i = 1; i < iterations; ++i)
{
auto outputPass = (i % 2 == 1) ? s_Data.BloomBlurPass[1] : s_Data.BloomBlurPass[0];
Renderer::BeginRenderPass(outputPass);
s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0);
s_Data.BloomBlurShader->SetBool("u_FirstPass", false);
if (i%2 == 1)
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->BindTexture();
else
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->BindTexture();
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
Renderer::BeginRenderPass(s_Data.BloomBlendPass); Renderer::BeginRenderPass(s_Data.BloomBlendPass);
s_Data.BloomBlurShader->Bind(); s_Data.BloomBlurShader->Bind();
s_Data.BloomBlurShader->SetInt("u_Texture", 0); s_Data.BloomBlurShader->SetInt("u_Texture", 0);
if (iterations % 2 == 0)
s_Data.BloomBlurPass[1]->GetSpecification().TargetFramebuffer->BindTexture();
else
s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer->BindTexture();
s_Data.BloomBlurShader->SetBool("u_FirstPass", false); s_Data.BloomBlurShader->SetBool("u_FirstPass", false);
s_Data.BloomBlurShader->SetInt("u_Quality", s_Data.Quality);
s_Data.BloomBlurShader->SetFloat("u_Directions", s_Data.Directions);
s_Data.BloomBlurShader->SetFloat("u_Size", s_Data.Size);
Renderer::Submit([finalBlurTex]() { glBindTextureUnit(0, finalBlurTex); });
Renderer::SubmitFullscreenQuad(nullptr); Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
void Renderer3D::GridPass()
void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass)
{ {
Renderer::BeginRenderPass(outRenderPass); Renderer::BeginRenderPass(s_Data.GeoPass, false);
s_Data.CompositeShader->Bind();
s_Data.CompositeShader->SetBool("u_EnableAutoExposure", s_Data.AutoExposureData.EnableAutoExposure);
s_Data.CompositeShader->SetFloat("u_ManualExposure", s_Data.SceneData.SceneCamera.Camera.GetExposure());
s_Data.CompositeShader->SetBool("u_EnableBloom", s_Data.EnableBloom);
s_Data.LightingPass->GetSpecification().TargetFramebuffer->BindTexture(); // 通常绑定到单元0
Renderer::Submit([]() {
glBindTextureUnit(1, s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID());
});
if (s_Data.EnableBloom)
{
uint32_t bloomTex = s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->GetColorAttachmentRendererID();
Renderer::Submit([bloomTex]() {
glBindTextureUnit(2, bloomTex);
});
s_Data.CompositeShader->SetInt("u_BloomTexture", 2);
}
s_Data.AutoExposureData.ExposureSSBO->BindBase(2);
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
void Renderer3D::OverlayPass(const Ref<RenderPass>& outRenderPass)
{
Renderer::BeginRenderPass(outRenderPass, false);
if (const auto option = GetOptions(); option.ShowGrid) if (const auto option = GetOptions(); option.ShowGrid)
{ {
Renderer::Submit([]() {
glDepthMask(GL_FALSE);
});
const auto& sceneCamera = s_Data.SceneData.SceneCamera; const auto& sceneCamera = s_Data.SceneData.SceneCamera;
const auto cameraProjection = sceneCamera.Camera.GetProjectionMatrix(); const auto cameraProjection = sceneCamera.Camera.GetProjectionMatrix();
@ -1181,11 +932,71 @@ namespace Prism
s_Data.GridData.GridMaterial->Set("u_FadeDistance", s_Data.GridData.FadeDistance); s_Data.GridData.GridMaterial->Set("u_FadeDistance", s_Data.GridData.FadeDistance);
Renderer::SubmitFullscreenQuad(s_Data.GridData.GridMaterial); Renderer::SubmitFullscreenQuad(s_Data.GridData.GridMaterial);
Renderer::Submit([]() {
glDepthMask(GL_TRUE);
});
} }
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
void CopyDepthBuffer(Ref<FrameBuffer> src, Ref<FrameBuffer> dst)
{
uint32_t srcID = src->GetRendererID(); // 假设 FrameBuffer 有此方法
uint32_t dstID = dst->GetRendererID();
int srcWidth = src->GetWidth();
int srcHeight = src->GetHeight();
int dstWidth = dst->GetWidth();
int dstHeight = dst->GetHeight();
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcID);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstID);
glBlitFramebuffer(0, 0, srcWidth, srcHeight, 0, 0, dstWidth, dstHeight,
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0); // 可选恢复
}
void Renderer3D::CompositePass(const Ref<RenderPass>& outRenderPass)
{
Renderer::Submit([srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer,
dstFB = outRenderPass->GetSpecification().TargetFramebuffer]()
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFB->GetRendererID());
glBlitFramebuffer(0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
0, 0, dstFB->GetWidth(), dstFB->GetHeight(),
GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
});
Renderer::BeginRenderPass(outRenderPass);
s_Data.CompositeShader->Bind();
s_Data.AutoExposureData.ExposureSSBO->BindBase(2);
s_Data.CompositeShader->SetBool("u_EnableAutoExposure", s_Data.AutoExposureData.EnableAutoExposure);
s_Data.CompositeShader->SetFloat("u_ManualExposure", s_Data.SceneData.SceneCamera.Camera.GetExposure());
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
s_Data.CompositeShader->SetBool("u_EnableBloom", s_Data.EnableBloom);
// 绑定几何阶段颜色纹理(多重采样)
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindDepthTexture(1);
if (s_Data.EnableBloom)
{
s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->BindTexture(0, 2);
s_Data.CompositeShader->SetInt("u_BloomTexture", 2); // 告诉着色器使用单元2
}
Renderer::SubmitFullscreenQuad(nullptr);
Renderer::EndRenderPass();
}
std::vector<glm::vec3> GetFrustumCornersWorldSpace(const SceneRendererCamera& sceneCamera) std::vector<glm::vec3> GetFrustumCornersWorldSpace(const SceneRendererCamera& sceneCamera)
{ {
@ -1212,6 +1023,39 @@ namespace Prism
} }
void Renderer3D::ResolveMSAA()
{
auto srcFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
const uint32_t width = srcFB->GetWidth();
const uint32_t height = srcFB->GetHeight();
if (!s_Data.ResolvedHDRTexture ||
s_Data.ResolvedHDRTexture->GetWidth() != width ||
s_Data.ResolvedHDRTexture->GetHeight() != height)
{
s_Data.ResolvedHDRTexture = Texture2D::Create(TextureFormat::RGBA16F, width, height);
}
Renderer::Submit([srcFB, resolvedTex = s_Data.ResolvedHDRTexture]() {
GLuint resolveFBO;
glGenFramebuffers(1, &resolveFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolvedTex->GetRendererID(), 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, srcFB->GetRendererID());
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
0, 0, srcFB->GetWidth(), srcFB->GetHeight(),
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glDeleteFramebuffers(1, &resolveFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
});
}
void SceneRenderer::OnImGuiRender() void SceneRenderer::OnImGuiRender()
{ {
ImGui::Begin("Scene Renderer"); ImGui::Begin("Scene Renderer");
@ -1219,37 +1063,9 @@ namespace Prism
UI::Property("Geometry Pass time", s_Stats.GeometryPass); UI::Property("Geometry Pass time", s_Stats.GeometryPass);
UI::Property("Composite Pass time", s_Stats.CompositePass); UI::Property("Composite Pass time", s_Stats.CompositePass);
UI::Property("Bloom Pass time", s_Stats.BloomPass);
UI::Property("Shadow Pass time", s_Stats.ShadowPass); UI::Property("Shadow Pass time", s_Stats.ShadowPass);
UI::Property("AutoExposure Pass time", s_Stats.AutoExposurePass); UI::Property("AutoExposure Pass time", s_Stats.AutoExposurePass);
if (UI::BeginTreeNode("Geometry", false))
{
const float size = ImGui::GetContentRegionAvail().x; // (float)fb->GetWidth() * 0.5f, (float)fb->GetHeight() * 0.5f
float w = size;
auto fb = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
auto image1 = fb->GetColorAttachmentRendererID(0);
auto image2 = fb->GetColorAttachmentRendererID(1);
auto image3 = fb->GetColorAttachmentRendererID(2);
float h = w / ((float)fb->GetWidth() / (float)fb->GetHeight());
ImGui::Image((ImTextureID)image1, { w, h }, { 0, 1 }, { 1, 0 });
ImGui::Image((ImTextureID)image2, { w, h }, { 0, 1 }, { 1, 0 });
ImGui::Image((ImTextureID)image3, { w, h }, { 0, 1 }, { 1, 0 });
auto lightFB = s_Data.LightingPass->GetSpecification().TargetFramebuffer;
auto lightImage = lightFB->GetColorAttachmentRendererID();
ImGui::Image((ImTextureID)lightImage, { w, h }, { 0, 1 }, { 1, 0 });
auto depthfb = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
uint32_t depthID = depthfb->GetDepthAttachmentRendererID();
ImGui::Image((ImTextureID)depthID, {w, h}, {0, 1}, {1, 0});
UI::EndTreeNode();
}
if (UI::BeginTreeNode("Grid Config", false)) if (UI::BeginTreeNode("Grid Config", false))
{ {
// Grid plane: 0 = XZ (Y up), 1 = XY (Z forward), 2 = YZ (X right) // Grid plane: 0 = XZ (Y up), 1 = XY (Z forward), 2 = YZ (X right)
@ -1310,10 +1126,6 @@ namespace Prism
UI::BeginPropertyGrid(); UI::BeginPropertyGrid();
UI::Property("Bloom", s_Data.EnableBloom); UI::Property("Bloom", s_Data.EnableBloom);
UI::Property("Bloom threshold", s_Data.BloomThreshold, 0.05f); UI::Property("Bloom threshold", s_Data.BloomThreshold, 0.05f);
UI::Property("Directions", s_Data.Directions);
UI::Property("Quality", s_Data.Quality);
UI::Property("Size", s_Data.Size);
UI::EndPropertyGrid(); UI::EndPropertyGrid();
auto fb = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer; auto fb = s_Data.BloomBlurPass[0]->GetSpecification().TargetFramebuffer;
@ -1327,9 +1139,11 @@ namespace Prism
float h = w / ((float)fb->GetWidth() / (float)fb->GetHeight()); float h = w / ((float)fb->GetWidth() / (float)fb->GetHeight());
ImGui::Image((ImTextureID)id, { w, h }, { 0, 1 }, { 1, 0 }); ImGui::Image((ImTextureID)id, { w, h }, { 0, 1 }, { 1, 0 });
ImGui::Image((ImTextureID)id2, { w, h }, { 0, 1 }, { 1, 0 }); ImGui::Image((ImTextureID)id2, { w, h }, { 0, 1 }, { 1, 0 });
ImGui::Image((ImTextureID)s_Data.ResolvedHDRTexture->GetRendererID(), { w, h }, { 0, 1 }, { 1, 0 });
UI::EndTreeNode(); UI::EndTreeNode();
} }
if (UI::BeginTreeNode("Auto Exposure", false)) if (UI::BeginTreeNode("Auto Exposure", false))
{ {
UI::BeginPropertyGrid(); UI::BeginPropertyGrid();
@ -1362,4 +1176,5 @@ namespace Prism
ImGui::End(); ImGui::End();
} }
} }

View File

@ -33,8 +33,8 @@ namespace Prism
static void BeginScene(const Scene* scene, const SceneRendererCamera& camera); static void BeginScene(const Scene* scene, const SceneRendererCamera& camera);
static void EndScene(Ref<RenderPass>& renderPass); static void EndScene(Ref<RenderPass>& renderPass);
static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const Ref<MaterialInstance>& overrideMaterial = nullptr); static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const std::vector<Ref<MaterialInstance>>& overrideMaterials = {});
static void SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f)); static void SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const std::vector<Ref<MaterialInstance>>& overrideMaterials = {});
static void SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); static void SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
static void SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); static void SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
@ -54,6 +54,7 @@ namespace Prism
static SceneRendererOptions& GetOptions(); static SceneRendererOptions& GetOptions();
static Ref<TextureCube> GetBlackCubeTexture(); static Ref<TextureCube> GetBlackCubeTexture();
static Ref<Texture2D> GetBlackTexture();
private: private:
static void FlushDrawList(Ref<RenderPass>& outRenderPass); static void FlushDrawList(Ref<RenderPass>& outRenderPass);
@ -61,15 +62,13 @@ namespace Prism
static void AutoExposurePass(); static void AutoExposurePass();
static void ShadowMapPass(); static void ShadowMapPass();
static void GeometryPass(); static void GeometryPass();
static void LightingPass();
static void BloomBlurPass(); static void BloomBlurPass();
static void GridPass();
static void OverlayPass(const Ref<RenderPass>& outRenderPass);
static void CompositePass(const Ref<RenderPass>& outRenderPass); static void CompositePass(const Ref<RenderPass>& outRenderPass);
// static void ResolveMSAA(); static void ResolveMSAA();
}; };
} }

View File

@ -12,6 +12,7 @@
#include "Renderer3D.h" #include "Renderer3D.h"
#include "RenderPass.h" #include "RenderPass.h"
#include "glad/glad.h"
namespace Prism namespace Prism
@ -26,7 +27,7 @@ namespace Prism
void SceneRenderer::Init() void SceneRenderer::Init()
{ {
FramebufferSpecification finalFramebufferSpec; FramebufferSpecification finalFramebufferSpec;
finalFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::DEPTH24STENCIL8}; finalFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA32F, FramebufferTextureFormat::DEPTH24STENCIL8};
finalFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f }; finalFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
RenderPassSpecification finalRenderPassSpec; RenderPassSpecification finalRenderPassSpec;
@ -141,14 +142,14 @@ namespace Prism
//////////////////// 3D API //////////////////// //////////////////// 3D API ////////////////////
void SceneRenderer::SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial) void SceneRenderer::SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials)
{ {
Renderer3D::SubmitMesh(mesh, transform, overrideMaterial); Renderer3D::SubmitMesh(mesh, transform, overrideMaterials);
} }
void SceneRenderer::SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform) void SceneRenderer::SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials)
{ {
Renderer3D::SubmitSelectedMesh(mesh, transform); Renderer3D::SubmitSelectedMesh(mesh, transform, overrideMaterials);
} }
void SceneRenderer::SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform) void SceneRenderer::SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform)
@ -207,4 +208,24 @@ namespace Prism
{ {
return Renderer3D::GetOptions(); return Renderer3D::GetOptions();
} }
void SceneRenderer::FlushToScreen()
{
const auto fb = s_Data.FinalPass->GetSpecification().TargetFramebuffer;
const auto fbWidth = fb->GetWidth();
const auto fbHeight = fb->GetHeight();
Renderer::Submit([fb, fbWidth, fbHeight]()
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb->GetColorAttachmentRendererID());
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, fbWidth, fbHeight,
0, 0, fbWidth, fbHeight,
GL_COLOR_BUFFER_BIT,
GL_NEAREST);
});
}
} }

View File

@ -15,7 +15,7 @@ namespace Prism
{ {
struct SceneRendererOptions struct SceneRendererOptions
{ {
bool ShowGrid = true; bool ShowGrid = false;
bool ShowBoundingBoxes = false; bool ShowBoundingBoxes = false;
}; };
@ -70,8 +70,8 @@ namespace Prism
// Renderer3D // Renderer3D
static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const Ref<MaterialInstance>& overrideMaterial = nullptr); static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const std::vector<Ref<MaterialInstance>>& overrideMaterials = {});
static void SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f)); static void SubmitSelectedMesh(const Ref<Mesh>& mesh, const glm::mat4& transform = glm::mat4(1.0f), const std::vector<Ref<MaterialInstance>>& overrideMaterials = {});
static void SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); static void SubmitColliderMesh(const BoxColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
static void SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f)); static void SubmitColliderMesh(const SphereColliderComponent& component, const glm::mat4& parentTransform = glm::mat4(1.0f));
@ -90,7 +90,9 @@ namespace Prism
static uint32_t GetFinalColorBufferRendererID(); static uint32_t GetFinalColorBufferRendererID();
static SceneRendererOptions& GetOptions(); static SceneRendererOptions& GetOptions();
static void OnImGuiRender(); static void OnImGuiRender();
private:
static void FlushToScreen();
}; };
} }

View File

@ -38,6 +38,16 @@ namespace Prism
return nullptr; return nullptr;
} }
Ref<Texture2D> Texture2D::Create(TextureFormat format, unsigned int width, unsigned int height, const void* data, TextureWrap wrap)
{
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: return Ref<OpenGLTexture2D>::Create(format, width, height, data, wrap);
}
return nullptr;
}
Ref<Texture2D> Texture2D::Create(const std::string& path, bool srgb) Ref<Texture2D> Texture2D::Create(const std::string& path, bool srgb)
{ {

View File

@ -5,9 +5,9 @@
#ifndef TEXTURE_H #ifndef TEXTURE_H
#define TEXTURE_H #define TEXTURE_H
#include "RendererAPI.h" #include "RendererAPI.h"
#include "Prism/Asset/Asset.h"
#include "Prism/Core/Buffer.h" #include "Prism/Core/Buffer.h"
#include "Prism/Core/Ref.h" #include "Prism/Core/Ref.h"
#include "../Asset/Asset.h"
namespace Prism namespace Prism
@ -53,6 +53,7 @@ namespace Prism
{ {
public: public:
static Ref<Texture2D> Create(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap = TextureWrap::Clamp); static Ref<Texture2D> Create(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap = TextureWrap::Clamp);
static Ref<Texture2D> Create(TextureFormat format, unsigned int width, unsigned int height, const void* data, TextureWrap wrap = TextureWrap::Clamp);
static Ref<Texture2D> Create(const std::string& path, bool srgb = false); static Ref<Texture2D> Create(const std::string& path, bool srgb = false);
@ -62,7 +63,7 @@ namespace Prism
virtual void Lock() = 0; virtual void Lock() = 0;
virtual void Unlock() = 0; virtual void Unlock() = 0;
virtual void SetData(const void* data, int count) = 0; virtual void SetData(const void* data, uint32_t count) = 0;
virtual void Resize(uint32_t width, uint32_t height) = 0; virtual void Resize(uint32_t width, uint32_t height) = 0;
virtual Buffer GetWriteableBuffer() = 0; virtual Buffer GetWriteableBuffer() = 0;

View File

@ -81,8 +81,9 @@ namespace Prism
} }
glm::mat4 GetTransform() const glm::mat4 GetTransform() const
{ {
return glm::translate(glm::mat4(1.0f), Translation) return glm::translate(glm::mat4(1.0f), Translation)
* glm::toMat4(glm::quat((Rotation))) * glm::toMat4(glm::quat(Rotation))
* glm::scale(glm::mat4(1.0f), Scale); * glm::scale(glm::mat4(1.0f), Scale);
} }
}; };
@ -91,32 +92,112 @@ namespace Prism
struct MeshComponent struct MeshComponent
{ {
Ref<Mesh> Mesh; Ref<Mesh> Mesh;
// std::vector<Ref<MaterialInstance>> Materials; std::vector<Ref<MaterialInstance>> MaterialInstances;
std::vector<Ref<PBRMaterialAsset>> MaterialDescs;
MeshComponent() = default; MeshComponent() = default;
MeshComponent(const MeshComponent& other) = default; MeshComponent(const MeshComponent& other)
: Mesh(other.Mesh)
{
MaterialInstances.clear();
MaterialDescs.clear();
for (auto i = 0; i < other.MaterialInstances.size(); i ++)
{
Ref<MaterialInstance> materialInstance = MaterialInstance::Copy(other.MaterialInstances[i]);
MaterialInstances.push_back(materialInstance);
MaterialDescs.push_back(other.MaterialDescs[i]);
}
UpdateMaterials();
}
MeshComponent(const Ref<Prism::Mesh>& mesh) MeshComponent(const Ref<Prism::Mesh>& mesh)
: Mesh(mesh) {}
operator Ref<Prism::Mesh> () { return Mesh; }
/*
MeshComponent(Ref<Prism::Mesh> mesh)
: Mesh(mesh) : Mesh(mesh)
{ {
// 复制 Mesh 的材质实例,每个实体拥有独立副本 MaterialInstances.clear();
if (mesh) MaterialDescs.clear();
const auto& materialInstances = Mesh->GetMaterials();
for (const auto & i : materialInstances)
{ {
const auto& srcMaterials = mesh->GetMaterials(); Ref<MaterialInstance> materialInstance = MaterialInstance::Copy(i);
Materials.reserve(srcMaterials.size()); MaterialInstances.push_back(materialInstance);
for (auto& srcMat : srcMaterials) }
MaterialDescs.resize(materialInstances.size());
}
void UpdateMaterials(const int index = -1, bool forceUpdate = false)
{
if (index <= -1)
{
for (uint32_t i = 0; i < MaterialInstances.size(); i++)
{ {
auto newMat = MaterialInstance::Copy(srcMat); if (auto& desc = MaterialDescs[i])
Materials.push_back(newMat); {
if (!desc->IsDirty && !forceUpdate) continue;
MaterialInstances[i]->Set("u_AlbedoColor", desc->AlbedoColor);
MaterialInstances[i]->Set("u_AlbedoTexToggle", desc->AlbedoTexToggle);
MaterialInstances[i]->Set("u_AlbedoTexture", desc->AlbedoTexture);
MaterialInstances[i]->Set("u_NormalTexToggle", desc->NormalTexToggle);
MaterialInstances[i]->Set("u_NormalTexture", desc->NormalTexture);
MaterialInstances[i]->Set("u_Metalness", desc->Metalness);
MaterialInstances[i]->Set("u_MetalnessTexToggle", desc->MetalnessTexToggle);
MaterialInstances[i]->Set("u_MetalnessTexture", desc->MetalnessTexture);
MaterialInstances[i]->Set("u_Roughness", desc->Roughness);
MaterialInstances[i]->Set("u_RoughnessTexToggle", desc->RoughnessTexToggle);
MaterialInstances[i]->Set("u_RoughnessTexture", desc->RoughnessTexture);
}else
{
auto& baseMaterial = Mesh->GetMaterials();
MaterialInstances[i]->Set("u_AlbedoColor", baseMaterial[i]->Get<glm::vec3>("u_AlbedoColor"));
MaterialInstances[i]->Set("u_AlbedoTexToggle", baseMaterial[i]->Get<float>("u_AlbedoTexToggle"));
MaterialInstances[i]->Set("u_AlbedoTexture", baseMaterial[i]->TryGetResource<Texture2D>("u_AlbedoTexture"));
MaterialInstances[i]->Set("u_NormalTexToggle", baseMaterial[i]->Get<float>("u_NormalTexToggle"));
MaterialInstances[i]->Set("u_NormalTexture", baseMaterial[i]->TryGetResource<Texture2D>("u_NormalTexture"));
MaterialInstances[i]->Set("u_Metalness", baseMaterial[i]->Get<float>("u_Metalness"));
MaterialInstances[i]->Set("u_MetalnessTexToggle", baseMaterial[i]->Get<float>("u_MetalnessTexToggle"));
MaterialInstances[i]->Set("u_MetalnessTexture", baseMaterial[i]->TryGetResource<Texture2D>("u_MetalnessTexture"));
MaterialInstances[i]->Set("u_Roughness", baseMaterial[0]->Get<float>("u_Roughness"));
MaterialInstances[i]->Set("u_RoughnessTexToggle", baseMaterial[i]->Get<float>("u_RoughnessTexToggle"));
MaterialInstances[i]->Set("u_RoughnessTexture", baseMaterial[i]->TryGetResource<Texture2D>("u_RoughnessTexture"));
}
} }
}else
{
if (index >= MaterialInstances.size()) return;
const auto& desc = MaterialDescs[index];
if (desc)
{
MaterialInstances[index]->Set("u_AlbedoColor", desc->AlbedoColor);
MaterialInstances[index]->Set("u_AlbedoTexToggle", desc->AlbedoTexToggle);
MaterialInstances[index]->Set("u_AlbedoTexture", desc->AlbedoTexture);
MaterialInstances[index]->Set("u_NormalTexToggle", desc->NormalTexToggle);
MaterialInstances[index]->Set("u_NormalTexture", desc->NormalTexture);
MaterialInstances[index]->Set("u_Metalness", desc->Metalness);
MaterialInstances[index]->Set("u_MetalnessTexToggle", desc->MetalnessTexToggle);
MaterialInstances[index]->Set("u_MetalnessTexture", desc->MetalnessTexture);
MaterialInstances[index]->Set("u_Roughness", desc->Roughness);
MaterialInstances[index]->Set("u_RoughnessTexToggle", desc->RoughnessTexToggle);
MaterialInstances[index]->Set("u_RoughnessTexture", desc->RoughnessTexture);
}else
{
auto& baseMaterial = Mesh->GetMaterials();
MaterialInstances[index]->Set("u_AlbedoColor", baseMaterial[index]->Get<glm::vec3>("u_AlbedoColor"));
MaterialInstances[index]->Set("u_AlbedoTexToggle", baseMaterial[index]->Get<float>("u_AlbedoTexToggle"));
MaterialInstances[index]->Set("u_AlbedoTexture", baseMaterial[index]->TryGetResource<Texture2D>("u_AlbedoTexture"));
MaterialInstances[index]->Set("u_NormalTexToggle", baseMaterial[index]->Get<float>("u_NormalTexToggle"));
MaterialInstances[index]->Set("u_NormalTexture", baseMaterial[index]->TryGetResource<Texture2D>("u_NormalTexture"));
MaterialInstances[index]->Set("u_Metalness", baseMaterial[index]->Get<float>("u_Metalness"));
MaterialInstances[index]->Set("u_MetalnessTexToggle", baseMaterial[index]->Get<float>("u_MetalnessTexToggle"));
MaterialInstances[index]->Set("u_MetalnessTexture", baseMaterial[index]->TryGetResource<Texture2D>("u_MetalnessTexture"));
MaterialInstances[index]->Set("u_Roughness", baseMaterial[0]->Get<float>("u_Roughness"));
MaterialInstances[index]->Set("u_RoughnessTexToggle", baseMaterial[index]->Get<float>("u_RoughnessTexToggle"));
MaterialInstances[index]->Set("u_RoughnessTexture", baseMaterial[index]->TryGetResource<Texture2D>("u_RoughnessTexture"));
}
} }
} }
*/
operator Ref<Prism::Mesh> () { return Mesh; }
}; };
struct AnimationComponent struct AnimationComponent
@ -305,7 +386,7 @@ namespace Prism
{ {
float Radius = 0.5f; float Radius = 0.5f;
bool IsTrigger = false; bool IsTrigger = false;
Ref<PhysicsMaterial> Material; Ref<PhysicsMaterialAsset> Material;
// The mesh that will be drawn in the editor to show the collision bounds // The mesh that will be drawn in the editor to show the collision bounds
Ref<Mesh> DebugMesh; Ref<Mesh> DebugMesh;
@ -344,7 +425,7 @@ namespace Prism
glm::vec3 Size = { 1.0f, 1.0f, 1.0f }; glm::vec3 Size = { 1.0f, 1.0f, 1.0f };
glm::vec3 Offset = { 0.0f, 0.0f, 0.0f }; glm::vec3 Offset = { 0.0f, 0.0f, 0.0f };
bool IsTrigger = false; bool IsTrigger = false;
Ref<PhysicsMaterial> Material; Ref<PhysicsMaterialAsset> Material;
// The mesh that will be drawn in the editor to show the collision bounds // The mesh that will be drawn in the editor to show the collision bounds
Ref<Mesh> DebugMesh; Ref<Mesh> DebugMesh;
@ -358,7 +439,7 @@ namespace Prism
float Radius = 0.5f; float Radius = 0.5f;
float Height = 1.0f; float Height = 1.0f;
bool IsTrigger = false; bool IsTrigger = false;
Ref<PhysicsMaterial> Material; Ref<PhysicsMaterialAsset> Material;
Ref<Mesh> DebugMesh; Ref<Mesh> DebugMesh;
@ -373,7 +454,7 @@ namespace Prism
bool IsConvex = false; bool IsConvex = false;
bool IsTrigger = false; bool IsTrigger = false;
bool OverrideMesh = false; bool OverrideMesh = false;
Ref<PhysicsMaterial> Material; Ref<PhysicsMaterialAsset> Material;
MeshColliderComponent() = default; MeshColliderComponent() = default;
MeshColliderComponent(const MeshColliderComponent& other) = default; MeshColliderComponent(const MeshColliderComponent& other) = default;
@ -431,7 +512,7 @@ namespace Prism
bool ShowIcon = false; bool ShowIcon = false;
bool DynamicSky = false; bool DynamicSky = false;
glm::vec3 TurbidityAzimuthInclination = { 2.0, 0.0, 0.0 }; glm::vec3 TurbidityAzimuthInclination = { 2.0, 0.0, 1.0 };
SkyLightComponent(const Ref<Environment>& environment) SkyLightComponent(const Ref<Environment>& environment)
: SceneEnvironment(environment) : SceneEnvironment(environment)
@ -452,7 +533,7 @@ namespace Prism
MeshComponent, MeshComponent,
RigidBodyComponent, BoxColliderComponent, SphereColliderComponent, CapsuleColliderComponent, MeshColliderComponent, RigidBodyComponent, BoxColliderComponent, SphereColliderComponent, CapsuleColliderComponent, MeshColliderComponent,
AnimationComponent, AnimationComponent,
DirectionalLightComponent, SkyLightComponent, PointLightComponent, SpotLightComponent, DirectionalLightComponent, SkyLightComponent,
ScriptComponent, ScriptComponent,
CameraComponent CameraComponent
>; >;

View File

@ -32,12 +32,7 @@ namespace Prism
static uint32_t s_SceneIDCounter = 0; static uint32_t s_SceneIDCounter = 0;
Scene::Scene(const std::string& debugName, const bool isEditorScene, const bool runtime)
Scene::Scene(const std::string& debugName, const bool isEditorScene)
: m_SceneID(++s_SceneIDCounter), m_DebugName(debugName) : m_SceneID(++s_SceneIDCounter), m_DebugName(debugName)
{ {
m_Registry.on_construct<TransformComponent>().connect<&Physics2D::OnTransformConstruct>(); m_Registry.on_construct<TransformComponent>().connect<&Physics2D::OnTransformConstruct>();
@ -56,10 +51,11 @@ namespace Prism
Physics3D::CreateScene(); Physics3D::CreateScene();
} }
Init(); Init(runtime);
} }
Scene::~Scene() Scene::~Scene()
{ {
m_Registry.on_destroy<ScriptComponent>().disconnect(); m_Registry.on_destroy<ScriptComponent>().disconnect();
@ -68,20 +64,24 @@ namespace Prism
s_ActiveScenes.erase(m_SceneID); s_ActiveScenes.erase(m_SceneID);
} }
void Scene::Init() void Scene::Init(const bool runtime)
{ {
// const auto skyboxShader = Shader::Create("assets/shaders/Skybox.glsl"); const auto skyboxShader = Shader::Create("assets/shaders/Skybox.glsl");
// m_SkyboxMaterial = MaterialInstance::Create(Material::Create(skyboxShader)); m_SkyboxMaterial = MaterialInstance::Create(Material::Create(skyboxShader));
// m_SkyboxMaterial->SetFlag(MaterialFlag::DepthTest, false); m_SkyboxMaterial->SetFlag(MaterialFlag::DepthTest, false);
m_CameraIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/Camera.png");
m_LightIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/light.png");
if (!runtime)
{
m_CameraIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/Camera.png");
m_LightIcon = AssetsManager::GetAsset<Texture2D>("assets/editor/light.png");
}
} }
void Scene::OnShutdown() void Scene::OnShutdown()
{ {
b2DestroyWorld(m_Registry.get<Box2DWorldComponent>(m_SceneEntity).World); b2DestroyWorld(m_Registry.get<Box2DWorldComponent>(m_SceneEntity).World);
Physics3D::DestroyScene();
ScriptEngine::OnSceneDestruct(m_SceneID);
} }
void Scene::OnUpdate(TimeStep ts) void Scene::OnUpdate(TimeStep ts)
@ -91,14 +91,14 @@ namespace Prism
const auto sceneView = m_Registry.view<Box2DWorldComponent>(); const auto sceneView = m_Registry.view<Box2DWorldComponent>();
const auto& box2DWorld = m_Registry.get<Box2DWorldComponent>(sceneView.front()).World; const auto& box2DWorld = m_Registry.get<Box2DWorldComponent>(sceneView.front()).World;
int32_t velocityIterations = 6;
constexpr int32_t positionIterations = 2; constexpr int32_t positionIterations = 2;
// box2DWorld->Step(ts, velocityIterations, positionIterations);
b2World_Step(box2DWorld, ts, positionIterations); b2World_Step(box2DWorld, ts, positionIterations);
// Process Contact Envents box2d version 3.0^ should impl contact event after b2World_Step // Process Contact Envents box2d version 3.0^ should impl contact event after b2World_Step
Physics2D::ProcessContactEvents(box2DWorld); Physics2D::ProcessContactEvents(box2DWorld);
// Physics3D
Physics3D::Simulate(ts);
{ {
const auto view = m_Registry.view<RigidBody2DComponent>(); const auto view = m_Registry.view<RigidBody2DComponent>();
for (const auto entity : view) for (const auto entity : view)
@ -138,8 +138,6 @@ namespace Prism
} }
Physics3D::Simulate(ts);
// Update all entities // Update all entities
{ {
const auto view = m_Registry.view<ScriptComponent>(); const auto view = m_Registry.view<ScriptComponent>();
@ -150,6 +148,7 @@ namespace Prism
ScriptEngine::OnUpdateEntity(e, ts); ScriptEngine::OnUpdateEntity(e, ts);
} }
} }
} }
void Scene::OnRenderRuntime(const TimeStep ts) void Scene::OnRenderRuntime(const TimeStep ts)
@ -171,8 +170,7 @@ namespace Prism
// TODO: only one sky light at the moment! // TODO: only one sky light at the moment!
{ {
if (!m_Environment) m_Environment = Ref<Environment>::Create();
m_Environment = Ref<Environment>::Create(Renderer3D::GetBlackCubeTexture(), Renderer3D::GetBlackCubeTexture());
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>); const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
for (const auto entity : lights) for (const auto entity : lights)
{ {
@ -185,23 +183,40 @@ namespace Prism
} }
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
SceneRenderer::BeginScene(this, { static_cast<Camera>(camera), cameraViewMatrix }, false); SceneRenderer::BeginScene(this, { static_cast<Camera>(camera), cameraViewMatrix }, false);
{ {
const auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>); const auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
// this maybe not to set
// in Editor actually only one materialdesc will be changed
Ref<PBRMaterialAsset> materialAsset;
for (const auto entity : group) for (const auto entity : group)
{ {
const auto& [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity); const auto& [transformComponent, meshComponent] = group.get<TransformComponent, MeshComponent>(entity);
if (meshComponent.Mesh) if (meshComponent.Mesh)
{ {
for (auto i = 0; i < meshComponent.MaterialInstances.size(); i++)
{
if (meshComponent.MaterialDescs[i] && meshComponent.MaterialDescs[i]->IsDirty)
{
materialAsset = meshComponent.MaterialDescs[i];
meshComponent.UpdateMaterials(i);
}
}
meshComponent.Mesh->OnUpdate(ts); meshComponent.Mesh->OnUpdate(ts);
glm::mat4 transform = GetTransformRelativeToParent(Entity(entity, this)); glm::mat4 transform = GetTransformRelativeToParent(Entity(entity, this));
// TODO: Should we render (logically) // TODO: Should we render (logically)
SceneRenderer::SubmitMesh(meshComponent, transform); SceneRenderer::SubmitMesh(meshComponent, transform, meshComponent.MaterialInstances);
} }
} }
if (materialAsset) materialAsset->IsDirty = false;
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@ -224,7 +239,9 @@ namespace Prism
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
} }
SceneRenderer::FlushToScreen();
SceneRenderer::EndScene(); SceneRenderer::EndScene();
} }
void Scene::OnRenderEditor(const TimeStep ts, const EditorCamera& editorCamera) void Scene::OnRenderEditor(const TimeStep ts, const EditorCamera& editorCamera)
@ -236,7 +253,7 @@ namespace Prism
// TODO: only one sky light at the moment! // TODO: only one sky light at the moment!
{ {
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>); const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
if (!m_Environment) if (lights.empty())
m_Environment = Ref<Environment>::Create(Renderer3D::GetBlackCubeTexture(), Renderer3D::GetBlackCubeTexture()); m_Environment = Ref<Environment>::Create(Renderer3D::GetBlackCubeTexture(), Renderer3D::GetBlackCubeTexture());
if (!lights.empty()) if (!lights.empty())
{ {
@ -251,14 +268,13 @@ namespace Prism
m_Environment = skyLightComponent.SceneEnvironment; m_Environment = skyLightComponent.SceneEnvironment;
m_EnvironmentIntensity = skyLightComponent.Intensity; m_EnvironmentIntensity = skyLightComponent.Intensity;
if (m_Environment)
break; //TODO: this only support one environment SetSkybox(m_Environment->RadianceMap);
} }
} }
} }
if (m_Environment)
SetSkybox(m_Environment->RadianceMap);
m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod);
// TODO: this value should be storage and can modify // TODO: this value should be storage and can modify
// TODO: Renderer2D cannot blend with Renderer3D // TODO: Renderer2D cannot blend with Renderer3D
@ -271,21 +287,35 @@ namespace Prism
const auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>); const auto group = m_Registry.group<MeshComponent>(entt::get<TransformComponent>);
{ {
// in Editor actually only one materialdesc will be changed
Ref<PBRMaterialAsset> materialAsset;
for (const auto [entity, meshComponent, transformComponent]: group.each()) for (const auto [entity, meshComponent, transformComponent]: group.each())
{ {
Entity e = {entity, this}; Entity e = {entity, this};
if (meshComponent.Mesh) if (meshComponent.Mesh)
{ {
for (auto i = 0; i < meshComponent.MaterialInstances.size(); i++)
{
if (meshComponent.MaterialDescs[i] && meshComponent.MaterialDescs[i]->IsDirty)
{
materialAsset = meshComponent.MaterialDescs[i];
meshComponent.UpdateMaterials(i);
}
}
meshComponent.Mesh->OnUpdate(ts); meshComponent.Mesh->OnUpdate(ts);
glm::mat4 transform = GetTransformRelativeToParent(e); glm::mat4 transform = GetTransformRelativeToParent(e);
// TODO: Should we render (logically) // TODO: Should we render (logically)
if (m_SelectedEntity == entity) if (m_SelectedEntity == entity)
SceneRenderer::SubmitSelectedMesh(meshComponent, transform); SceneRenderer::SubmitSelectedMesh(meshComponent, transform, meshComponent.MaterialInstances);
else else
SceneRenderer::SubmitMesh(meshComponent, transform); SceneRenderer::SubmitMesh(meshComponent, transform, meshComponent.MaterialInstances);
} }
// Renderer Collider // Renderer Collider
@ -303,6 +333,8 @@ namespace Prism
SceneRenderer::SubmitColliderMesh(*collider, transform); SceneRenderer::SubmitColliderMesh(*collider, transform);
} }
} }
if (materialAsset) materialAsset->IsDirty = false;
} }
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@ -432,6 +464,12 @@ namespace Prism
m_IsPlaying = false; m_IsPlaying = false;
} }
void Scene::SetViewportSize(const glm::ivec2& viewportSize)
{
m_ViewportWidth = viewportSize.x;
m_ViewportHeight = viewportSize.y;
}
void Scene::SetViewportSize(const uint32_t width, const uint32_t height) void Scene::SetViewportSize(const uint32_t width, const uint32_t height)
{ {
m_ViewportWidth = width; m_ViewportWidth = width;
@ -441,6 +479,7 @@ namespace Prism
void Scene::SetSkybox(const Ref<TextureCube>& skybox) void Scene::SetSkybox(const Ref<TextureCube>& skybox)
{ {
m_SkyboxTexture = skybox; m_SkyboxTexture = skybox;
m_SkyboxMaterial->Set("u_Texture", skybox);
} }
Entity Scene::GetMainCameraEntity() Entity Scene::GetMainCameraEntity()
@ -579,8 +618,8 @@ namespace Prism
{ {
target->m_Environment = m_Environment; target->m_Environment = m_Environment;
target->m_SkyboxTexture = m_SkyboxTexture; target->m_SkyboxTexture = m_SkyboxTexture;
target->m_SkyboxMaterial = m_SkyboxMaterial;
target->m_SkyboxLod = m_SkyboxLod; target->m_SkyboxLod = m_SkyboxLod;
target->m_EnvironmentIntensity = m_EnvironmentIntensity;
std::unordered_map<UUID, entt::entity> enttMap; std::unordered_map<UUID, entt::entity> enttMap;
auto idComponents = m_Registry.view<IDComponent>(); auto idComponents = m_Registry.view<IDComponent>();
@ -646,33 +685,35 @@ namespace Prism
// Point Light // Point Light
{ {
const auto pointLights = m_Registry.group<PointLightComponent>(entt::get<TransformComponent>); const auto pointLights = m_Registry.group<PointLightComponent>(entt::get<TransformComponent>);
m_LightEnvironment.PointLightCount = 0; uint32_t pointLightIndex = 0;
for (const auto entity : pointLights) for (const auto entity : pointLights)
{ {
if (m_LightEnvironment.PointLightCount >= 16) break; if (pointLightIndex >= 8) break;
auto [transform, light] = pointLights.get<TransformComponent, PointLightComponent>(entity); auto [transform, light] = pointLights.get<TransformComponent, PointLightComponent>(entity);
m_LightEnvironment.PointLights[m_LightEnvironment.PointLightCount++] = { m_LightEnvironment.PointLights[pointLightIndex++] = {
transform.Translation, transform.Translation,
light.Radiance, light.Radiance,
light.Radius, light.Radius,
light.Intensity, light.Intensity,
light.CastShadows, light.CastShadows,
}; };
m_LightEnvironment.PointLightCount ++;
} }
} }
// Spot Light // Spot Light
{ {
const auto spotLights = m_Registry.group<SpotLightComponent>(entt::get<TransformComponent>); const auto spotLights = m_Registry.group<SpotLightComponent>(entt::get<TransformComponent>);
m_LightEnvironment.SpotLightCount = 0; uint32_t pointLightIndex = 0;
for (const auto entity : spotLights) for (const auto entity : spotLights)
{ {
if (m_LightEnvironment.SpotLightCount >= 16) break; if (pointLightIndex >= 8) break;
auto [transform, light] = spotLights.get<TransformComponent, SpotLightComponent>(entity); auto [transform, light] = spotLights.get<TransformComponent, SpotLightComponent>(entity);
const glm::vec3 direction = glm::normalize(glm::mat3(transform.GetTransform()) * glm::vec3(0.0f, 0.0f, 1.0f)); const glm::vec3 direction = glm::normalize(glm::mat3(transform.GetTransform()) * glm::vec3(0.0f, 0.0f, 1.0f));
const float innerCos = glm::cos(glm::radians(light.InnerConeAngle)); const float innerCos = glm::cos(glm::radians(light.InnerConeAngle));
const float outerCos = glm::cos(glm::radians(light.OuterConeAngle)); const float outerCos = glm::cos(glm::radians(light.OuterConeAngle));
m_LightEnvironment.SpotLights[m_LightEnvironment.SpotLightCount++] = { m_LightEnvironment.SpotLights[pointLightIndex++] = {
transform.Translation, transform.Translation,
direction, direction,
light.Radiance, light.Radiance,
@ -682,6 +723,7 @@ namespace Prism
outerCos, outerCos,
light.CastShadows, light.CastShadows,
}; };
m_LightEnvironment.SpotLightCount ++;
} }
} }
} }

View File

@ -54,10 +54,10 @@ namespace Prism
{ {
GPUDirectionalLight DirectionalLights[4]; GPUDirectionalLight DirectionalLights[4];
GPUPointLight PointLights[16]{}; GPUPointLight PointLights[8]{};
int PointLightCount = 0; int PointLightCount = 0;
GPUSpotLight SpotLights[16]{}; GPUSpotLight SpotLights[8]{};
int SpotLightCount = 0; int SpotLightCount = 0;
}; };
@ -74,10 +74,10 @@ namespace Prism
class PRISM_API Scene : public RefCounted class PRISM_API Scene : public RefCounted
{ {
public: public:
Scene(const std::string& debugName = "Scene", bool isEditorScene = false); Scene(const std::string& debugName = "Scene", bool isEditorScene = false, bool runtime = false);
~Scene(); ~Scene();
void Init(); void Init(bool runtime);
void OnShutdown(); void OnShutdown();
void OnUpdate(TimeStep ts); void OnUpdate(TimeStep ts);
@ -88,6 +88,7 @@ namespace Prism
void OnRuntimeStart(); void OnRuntimeStart();
void OnRuntimeStop(); void OnRuntimeStop();
void SetViewportSize(const glm::ivec2& viewportSize);
void SetViewportSize(uint32_t width, uint32_t height); void SetViewportSize(uint32_t width, uint32_t height);
const Ref<Environment>& GetEnvironment() const { return m_Environment; } const Ref<Environment>& GetEnvironment() const { return m_Environment; }
@ -164,10 +165,11 @@ namespace Prism
bool m_IsPlaying = false; bool m_IsPlaying = false;
Ref<Environment> m_Environment; Ref<Environment> m_Environment;
float m_EnvironmentIntensity = 1.0f;
Ref<TextureCube> m_SkyboxTexture; Ref<TextureCube> m_SkyboxTexture;
Ref<MaterialInstance> m_SkyboxMaterial;
float m_SkyboxLod = 0.0f; float m_SkyboxLod = 0.0f;
float m_EnvironmentIntensity = 1.0f;
Ref<Texture2D> m_CameraIcon; Ref<Texture2D> m_CameraIcon;

View File

@ -13,142 +13,13 @@
#include "Prism/Physics/PhysicsLayer.h" #include "Prism/Physics/PhysicsLayer.h"
#include "Prism/Physics/PhysicsWrappers.h" #include "Prism/Physics/PhysicsWrappers.h"
#include "Prism/Renderer/Meshfactory.h" #include "Prism/Renderer/Meshfactory.h"
#include "../Asset/AssetsManager.h" #include "Prism/Asset/AssetsManager.h"
namespace YAML #include "Prism/Utilities/SerializeUtils.h"
{
template<>
struct convert<glm::vec2>
{
static Node encode(const glm::vec2& rhs)
{
Node node;
node.push_back(rhs.x);
node.push_back(rhs.y);
return node;
}
static bool decode(const Node& node, glm::vec2& rhs)
{
if (!node.IsSequence() || node.size() != 2)
return false;
rhs.x = node[0].as<float>();
rhs.y = node[1].as<float>();
return true;
}
};
template<>
struct convert<glm::vec3>
{
static Node encode(const glm::vec3& rhs)
{
Node node;
node.push_back(rhs.x);
node.push_back(rhs.y);
node.push_back(rhs.z);
return node;
}
static bool decode(const Node& node, glm::vec3& rhs)
{
if (!node.IsSequence() || node.size() != 3)
return false;
rhs.x = node[0].as<float>();
rhs.y = node[1].as<float>();
rhs.z = node[2].as<float>();
return true;
}
};
template<>
struct convert<glm::vec4>
{
static Node encode(const glm::vec4& rhs)
{
Node node;
node.push_back(rhs.x);
node.push_back(rhs.y);
node.push_back(rhs.z);
node.push_back(rhs.w);
return node;
}
static bool decode(const Node& node, glm::vec4& rhs)
{
if (!node.IsSequence() || node.size() != 4)
return false;
rhs.x = node[0].as<float>();
rhs.y = node[1].as<float>();
rhs.z = node[2].as<float>();
rhs.w = node[3].as<float>();
return true;
}
};
template<>
struct convert<glm::quat>
{
static Node encode(const glm::quat& rhs)
{
Node node;
node.push_back(rhs.w);
node.push_back(rhs.x);
node.push_back(rhs.y);
node.push_back(rhs.z);
return node;
}
static bool decode(const Node& node, glm::quat& rhs)
{
if (!node.IsSequence() || node.size() != 4)
return false;
rhs.w = node[0].as<float>();
rhs.x = node[1].as<float>();
rhs.y = node[2].as<float>();
rhs.z = node[3].as<float>();
return true;
}
};
}
namespace Prism namespace Prism
{ {
YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec2& v)
{
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << YAML::EndSeq;
return out;
}
YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec3& v)
{
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq;
return out;
}
YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec4& v)
{
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq;
return out;
}
YAML::Emitter& operator<<(YAML::Emitter& out, const glm::quat& v)
{
out << YAML::Flow;
out << YAML::BeginSeq << v.w << v.x << v.y << v.z << YAML::EndSeq;
return out;
}
SceneSerializer::SceneSerializer(const Ref<Scene>& scene) SceneSerializer::SceneSerializer(const Ref<Scene>& scene)
: m_Scene(scene) : m_Scene(scene)
{ {
@ -163,7 +34,7 @@ namespace Prism
if (entity.HasComponent<RelationshipComponent>()) if (entity.HasComponent<RelationshipComponent>())
{ {
auto& relationshipComponent = entity.GetComponent<RelationshipComponent>(); const auto& relationshipComponent = entity.GetComponent<RelationshipComponent>();
out << YAML::Key << "Parent" << YAML::Value << relationshipComponent.ParentHandle; out << YAML::Key << "Parent" << YAML::Value << relationshipComponent.ParentHandle;
out << YAML::Key << "Children"; out << YAML::Key << "Children";
@ -258,11 +129,44 @@ namespace Prism
out << YAML::Key << "MeshComponent"; out << YAML::Key << "MeshComponent";
out << YAML::BeginMap; // MeshComponent out << YAML::BeginMap; // MeshComponent
const auto mesh = entity.GetComponent<MeshComponent>().Mesh; const auto& meshComponent = entity.GetComponent<MeshComponent>();
if (mesh) if (meshComponent.Mesh)
{
const auto& mesh = meshComponent.Mesh;
out << YAML::Key << "AssetID" << YAML::Value << mesh->Handle; out << YAML::Key << "AssetID" << YAML::Value << mesh->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << mesh->FilePath;
if (!meshComponent.MaterialDescs.empty())
{
out << YAML::Key << "Materials";
out << YAML::BeginMap;
for (auto i = 0; i < meshComponent.MaterialDescs.size(); ++i)
{
{
std::string slots = "Slot " + std::to_string(i);
out << YAML::Key << slots;
out << YAML::BeginMap;
if (meshComponent.MaterialDescs[i])
{
out << YAML::Key << "AssetHandle" << YAML::Value << meshComponent.MaterialDescs[i]->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << meshComponent.MaterialDescs[i]->FilePath;
}else
{
out << YAML::Key << "AssetHandle" << YAML::Value << 0;
out << YAML::Key << "AssetPath" << YAML::Value << "";
}
out << YAML::EndMap;
}
}
out << YAML::EndMap;
}
}
else else
{
out << YAML::Key << "AssetID" << YAML::Value << 0; out << YAML::Key << "AssetID" << YAML::Value << 0;
out << YAML::Key << "AssetPath" << YAML::Value << "";
}
out << YAML::EndMap; // MeshComponent out << YAML::EndMap; // MeshComponent
} }
@ -287,7 +191,16 @@ namespace Prism
out << YAML::BeginMap; // SkyLightComponent out << YAML::BeginMap; // SkyLightComponent
const auto& skyLightComponent = entity.GetComponent<SkyLightComponent>(); const auto& skyLightComponent = entity.GetComponent<SkyLightComponent>();
out << YAML::Key << "EnvironmentMap" << YAML::Value << skyLightComponent.SceneEnvironment->Handle; if (skyLightComponent.SceneEnvironment)
{
out << YAML::Key << "EnvironmentMap" << YAML::Value << skyLightComponent.SceneEnvironment->Handle;
out << YAML::Key << "EnvironmentAssetPath" << YAML::Value << skyLightComponent.SceneEnvironment->FilePath;
}
else
{
out << YAML::Key << "EnvironmentMap" << YAML::Value << 0;
out << YAML::Key << "EnvironmentAssetPath" << YAML::Value << "";
}
out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity; out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity;
out << YAML::Key << "Angle" << YAML::Value << skyLightComponent.Angle; out << YAML::Key << "Angle" << YAML::Value << skyLightComponent.Angle;
@ -518,9 +431,16 @@ namespace Prism
out << YAML::Key << "IsTrigger" << YAML::Value << boxColliderComponent.IsTrigger; out << YAML::Key << "IsTrigger" << YAML::Value << boxColliderComponent.IsTrigger;
if (boxColliderComponent.Material) if (boxColliderComponent.Material)
{
out << YAML::Key << "Material" << YAML::Value << boxColliderComponent.Material->Handle; out << YAML::Key << "Material" << YAML::Value << boxColliderComponent.Material->Handle;
out << YAML::Key << "MaterialPath" << YAML::Value << boxColliderComponent.Material->FilePath;
}
else else
{
out << YAML::Key << "Material" << YAML::Value << 0; out << YAML::Key << "Material" << YAML::Value << 0;
out << YAML::Key << "MaterialPath" << YAML::Value << "";
}
out << YAML::EndMap; // BoxColliderComponent out << YAML::EndMap; // BoxColliderComponent
} }
@ -535,9 +455,16 @@ namespace Prism
out << YAML::Key << "IsTrigger" << YAML::Value << sphereColliderComponent.IsTrigger; out << YAML::Key << "IsTrigger" << YAML::Value << sphereColliderComponent.IsTrigger;
if (sphereColliderComponent.Material) if (sphereColliderComponent.Material)
{
out << YAML::Key << "Material" << YAML::Value << sphereColliderComponent.Material->Handle; out << YAML::Key << "Material" << YAML::Value << sphereColliderComponent.Material->Handle;
out << YAML::Key << "MaterialPath" << YAML::Value << sphereColliderComponent.Material->FilePath;
}
else else
{
out << YAML::Key << "Material" << YAML::Value << 0; out << YAML::Key << "Material" << YAML::Value << 0;
out << YAML::Key << "MaterialPath" << YAML::Value << "";
}
out << YAML::EndMap; // SphereColliderComponent out << YAML::EndMap; // SphereColliderComponent
} }
@ -552,10 +479,18 @@ namespace Prism
out << YAML::Key << "Height" << YAML::Value << capsuleColliderComponent.Height; out << YAML::Key << "Height" << YAML::Value << capsuleColliderComponent.Height;
out << YAML::Key << "IsTrigger" << YAML::Value << capsuleColliderComponent.IsTrigger; out << YAML::Key << "IsTrigger" << YAML::Value << capsuleColliderComponent.IsTrigger;
if (capsuleColliderComponent.Material) if (capsuleColliderComponent.Material)
{
out << YAML::Key << "Material" << YAML::Value << capsuleColliderComponent.Material->Handle; out << YAML::Key << "Material" << YAML::Value << capsuleColliderComponent.Material->Handle;
out << YAML::Key << "MaterialPath" << YAML::Value << capsuleColliderComponent.Material->FilePath;
}
else else
{
out << YAML::Key << "Material" << YAML::Value << 0; out << YAML::Key << "Material" << YAML::Value << 0;
out << YAML::Key << "MaterialPath" << YAML::Value << "";
}
out << YAML::EndMap; // CapsuleColliderComponent out << YAML::EndMap; // CapsuleColliderComponent
} }
@ -565,19 +500,27 @@ namespace Prism
out << YAML::Key << "MeshColliderComponent"; out << YAML::Key << "MeshColliderComponent";
out << YAML::BeginMap; // MeshColliderComponent out << YAML::BeginMap; // MeshColliderComponent
auto meshColliderComponent = entity.GetComponent<MeshColliderComponent>(); const auto& meshColliderComponent = entity.GetComponent<MeshColliderComponent>();
if (meshColliderComponent.OverrideMesh && meshColliderComponent.CollisionMesh)
if (meshColliderComponent.OverrideMesh) {
out << YAML::Key << "AssetID" << YAML::Value << meshColliderComponent.CollisionMesh->Handle; out << YAML::Key << "AssetID" << YAML::Value << meshColliderComponent.CollisionMesh->Handle;
out << YAML::Key << "AssetPath" << YAML::Value << meshColliderComponent.CollisionMesh->FilePath;
}
out << YAML::Key << "IsConvex" << YAML::Value << meshColliderComponent.IsConvex; out << YAML::Key << "IsConvex" << YAML::Value << meshColliderComponent.IsConvex;
out << YAML::Key << "IsTrigger" << YAML::Value << meshColliderComponent.IsTrigger; out << YAML::Key << "IsTrigger" << YAML::Value << meshColliderComponent.IsTrigger;
out << YAML::Key << "OverrideMesh" << YAML::Value << meshColliderComponent.OverrideMesh; out << YAML::Key << "OverrideMesh" << YAML::Value << meshColliderComponent.OverrideMesh;
if (meshColliderComponent.Material) if (meshColliderComponent.Material)
{
out << YAML::Key << "Material" << YAML::Value << meshColliderComponent.Material->Handle; out << YAML::Key << "Material" << YAML::Value << meshColliderComponent.Material->Handle;
out << YAML::Key << "MaterialPath" << YAML::Value << meshColliderComponent.Material->FilePath;
}
else else
{
out << YAML::Key << "Material" << YAML::Value << 0; out << YAML::Key << "Material" << YAML::Value << 0;
out << YAML::Key << "MaterialPath" << YAML::Value << "";
}
out << YAML::EndMap; // MeshColliderComponent out << YAML::EndMap; // MeshColliderComponent
} }
@ -829,7 +772,7 @@ namespace Prism
if (meshComponent["AssetPath"]) if (meshComponent["AssetPath"])
{ {
const std::string assetFilePath = meshComponent["AssetPath"].as<std::string>(); const std::string assetFilePath = meshComponent["AssetPath"].as<std::string>();
assetID = AssetsManager::GetAssetHandleFromFilePath(filepath); assetID = AssetsManager::GetAssetHandleFromFilePath(assetFilePath);
} }
else else
{ {
@ -838,7 +781,46 @@ namespace Prism
if (AssetsManager::IsAssetHandleValid(assetID) && !deserializedEntity.HasComponent<MeshComponent>()) if (AssetsManager::IsAssetHandleValid(assetID) && !deserializedEntity.HasComponent<MeshComponent>())
{ {
deserializedEntity.AddComponent<MeshComponent>(AssetsManager::GetAsset<Mesh>(assetID)); auto& mc = deserializedEntity.AddComponent<MeshComponent>(AssetsManager::GetAsset<Mesh>(assetID));
if (meshComponent["Materials"])
{
auto materialsNode = meshComponent["Materials"];
// 遍历 "Slot X" 键
for (auto it = materialsNode.begin(); it != materialsNode.end(); ++it)
{
std::string slotKey = it->first.as<std::string>();
if (slotKey.rfind("Slot ", 0) == 0) // 确保是 "Slot X"
{
int slotIndex = std::stoi(slotKey.substr(5));
auto slotNode = it->second;
// 获取材质资产的 Handle
UUID materialHandle = 0;
if (slotNode["AssetPath"])
{
std::string matPath = slotNode["AssetPath"].as<std::string>();
if (!matPath.empty())
materialHandle = AssetsManager::GetAssetHandleFromFilePath(matPath);
}
else if (slotNode["AssetHandle"])
{
materialHandle = slotNode["AssetHandle"].as<uint64_t>();
}
// 调整 MaterialDescs 大小(确保索引有效)
if (slotIndex >= mc.MaterialDescs.size())
mc.MaterialDescs.resize(slotIndex + 1);
// 加载材质资产并赋值
if (materialHandle != 0 && AssetsManager::IsAssetHandleValid(materialHandle))
mc.MaterialDescs[slotIndex] = AssetsManager::GetAsset<PBRMaterialAsset>(materialHandle);
else
mc.MaterialDescs[slotIndex] = nullptr;
}
}
mc.UpdateMaterials(-1, true);
}
} }
} }
@ -858,8 +840,8 @@ namespace Prism
AssetHandle assetHandle; AssetHandle assetHandle;
if (skyLightComponent["EnvironmentAssetPath"]) if (skyLightComponent["EnvironmentAssetPath"])
{ {
const auto filePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>(); const auto assetFilePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>();
assetHandle = AssetsManager::GetAssetHandleFromFilePath(filepath); assetHandle = AssetsManager::GetAssetHandleFromFilePath(assetFilePath);
} }
else else
{ {
@ -1054,10 +1036,18 @@ namespace Prism
auto material = boxColliderComponent["Material"]; auto material = boxColliderComponent["Material"];
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>())) if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
{ {
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>()); component.Material = AssetsManager::GetAsset<PhysicsMaterialAsset>(material.as<uint64_t>());
}else
{
const auto materialPath = boxColliderComponent["MaterialPath"].as<std::string>();
if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0)
{
component.Material = AssetsManager::GetAsset<PhysicsMaterialAsset>(assetId);
}
} }
component.DebugMesh = MeshFactory::CreateBox(component.Size);
component.DebugMesh = MeshFactory::CreateBox(component.Size * 2.0f);
} }
if (auto sphereColliderComponent = entity["SphereColliderComponent"]) if (auto sphereColliderComponent = entity["SphereColliderComponent"])
@ -1068,7 +1058,17 @@ namespace Prism
auto material = sphereColliderComponent["Material"]; auto material = sphereColliderComponent["Material"];
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>())) if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>()); {
component.Material = AssetsManager::GetAsset<PhysicsMaterialAsset>(material.as<uint64_t>());
}else
{
const auto materialPath = sphereColliderComponent["MaterialPath"].as<std::string>();
if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0)
{
component.Material = AssetsManager::GetAsset<PhysicsMaterialAsset>(assetId);
}
}
component.DebugMesh = MeshFactory::CreateSphere(component.Radius); component.DebugMesh = MeshFactory::CreateSphere(component.Radius);
} }
@ -1082,7 +1082,16 @@ namespace Prism
auto material = capsuleColliderComponent["Material"]; auto material = capsuleColliderComponent["Material"];
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>())) if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>()); {
component.Material = AssetsManager::GetAsset<PhysicsMaterialAsset>(material.as<uint64_t>());
}else
{
const auto materialPath = capsuleColliderComponent["MaterialPath"].as<std::string>();
if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0)
{
component.Material = AssetsManager::GetAsset<PhysicsMaterialAsset>(assetId);
}
}
component.DebugMesh = MeshFactory::CreateCapsule(component.Radius, component.Height); component.DebugMesh = MeshFactory::CreateCapsule(component.Radius, component.Height);
} }
@ -1095,14 +1104,14 @@ namespace Prism
if (overrideMesh) if (overrideMesh)
{ {
UUID assetID; UUID assetID;
if (meshComponent["AssetPath"]) if (meshColliderComponent["AssetPath"])
{ {
const auto assetFilePath = meshComponent["AssetPath"].as<std::string>(); const auto assetFilePath = meshColliderComponent["AssetPath"].as<std::string>();
assetID = AssetsManager::GetAssetHandleFromFilePath(filepath); assetID = AssetsManager::GetAssetHandleFromFilePath(assetFilePath);
} }
else else
{ {
assetID = meshComponent["AssetID"].as<uint64_t>(); assetID = meshColliderComponent["AssetID"].as<uint64_t>();
} }
if (AssetsManager::IsAssetHandleValid(assetID)) if (AssetsManager::IsAssetHandleValid(assetID))
@ -1116,16 +1125,33 @@ namespace Prism
component.IsTrigger = meshColliderComponent["IsTrigger"] ? meshColliderComponent["IsTrigger"].as<bool>() : false; component.IsTrigger = meshColliderComponent["IsTrigger"] ? meshColliderComponent["IsTrigger"].as<bool>() : false;
component.OverrideMesh = overrideMesh; component.OverrideMesh = overrideMesh;
auto material = meshColliderComponent["Material"]; if (meshColliderComponent["Material"])
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
{ {
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>()); auto material = meshColliderComponent["Material"];
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
{
component.Material = AssetsManager::GetAsset<PhysicsMaterialAsset>(material.as<uint64_t>());
if (component.IsConvex) if (component.IsConvex)
PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale); PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale);
else else
PhysicsWrappers::CreateTriangleMesh(component, deserializedEntity.Transform().Scale); PhysicsWrappers::CreateTriangleMesh(component, deserializedEntity.Transform().Scale);
}else
{
const auto materialPath = meshColliderComponent["MaterialPath"].as<std::string>();
if (const auto assetId = AssetsManager::GetAssetHandleFromFilePath(materialPath); assetId != 0)
{
component.Material = AssetsManager::GetAsset<PhysicsMaterialAsset>(assetId);
if (component.IsConvex)
PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale);
else
PhysicsWrappers::CreateTriangleMesh(component, deserializedEntity.Transform().Scale);
}
}
} }
} }
else else
{ {
@ -1139,7 +1165,7 @@ namespace Prism
if (physicsMaterialComponent) if (physicsMaterialComponent)
{ {
//auto& component = deserializedEntity.AddComponent<PhysicsMaterialComponent>(); //auto& component = deserializedEntity.AddComponent<PhysicsMaterialComponent>();
Ref<PhysicsMaterial> material = Ref<PhysicsMaterial>::Create(); Ref<PhysicsMaterialAsset> material = Ref<PhysicsMaterialAsset>::Create();
material->StaticFriction = physicsMaterialComponent["StaticFriction"].as<float>(); material->StaticFriction = physicsMaterialComponent["StaticFriction"].as<float>();
material->DynamicFriction = physicsMaterialComponent["DynamicFriction"].as<float>(); material->DynamicFriction = physicsMaterialComponent["DynamicFriction"].as<float>();
material->Bounciness = physicsMaterialComponent["Bounciness"].as<float>(); material->Bounciness = physicsMaterialComponent["Bounciness"].as<float>();

View File

@ -3,6 +3,7 @@
// //
#include "ScriptEngine.h" #include "ScriptEngine.h"
#include <cstddef>
#include <filesystem> #include <filesystem>
@ -35,6 +36,10 @@ namespace Prism
MonoImage* s_AppAssemblyImage = nullptr; MonoImage* s_AppAssemblyImage = nullptr;
MonoImage* s_CoreAssemblyImage = nullptr; MonoImage* s_CoreAssemblyImage = nullptr;
std::vector<std::string> ScriptEngine::s_AvailableScripts;
#ifdef ENABLE_MONO_DEBUG #ifdef ENABLE_MONO_DEBUG
static bool s_EnableMonoPDBDebug = true; static bool s_EnableMonoPDBDebug = true;
#else #else
@ -87,6 +92,7 @@ namespace Prism
static std::unordered_map<std::string, EntityScriptClass> s_EntityClassMap; static std::unordered_map<std::string, EntityScriptClass> s_EntityClassMap;
MonoAssembly* LoadAssemblyFromFile(const char* filepath) MonoAssembly* LoadAssemblyFromFile(const char* filepath)
{ {
if (!filepath) { if (!filepath) {
@ -390,6 +396,12 @@ namespace Prism
void ScriptEngine::Init(const std::string& assemblyPath) void ScriptEngine::Init(const std::string& assemblyPath)
{ {
#ifdef _WIN32
_putenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1");
#else
setenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", 1);
#endif
s_AssemblyPath = assemblyPath; s_AssemblyPath = assemblyPath;
InitMono(); InitMono();
@ -429,8 +441,8 @@ namespace Prism
s_CoreAssembly = LoadAssembly("assets/scripts/Prism-ScriptCore.dll"); s_CoreAssembly = LoadAssembly("assets/scripts/Prism-ScriptCore.dll");
s_CoreAssemblyImage = GetAssemblyImage(s_CoreAssembly); s_CoreAssemblyImage = GetAssemblyImage(s_CoreAssembly);
auto appAssembly = LoadAssembly(path); const auto appAssembly = LoadAssembly(path);
auto appAssemblyImage = GetAssemblyImage(appAssembly); const auto appAssemblyImage = GetAssemblyImage(appAssembly);
ScriptEngineRegistry::RegisterAll(); ScriptEngineRegistry::RegisterAll();
if (cleanup) if (cleanup)
@ -441,6 +453,8 @@ namespace Prism
s_AppAssembly = appAssembly; s_AppAssembly = appAssembly;
s_AppAssemblyImage = appAssemblyImage; s_AppAssemblyImage = appAssemblyImage;
RefreshAvailableScripts();
} }
void ScriptEngine::ReloadAssembly(const std::string& path) void ScriptEngine::ReloadAssembly(const std::string& path)
@ -845,6 +859,43 @@ namespace Prism
return entityIDMap.at(entityID); return entityIDMap.at(entityID);
} }
void ScriptEngine::RefreshAvailableScripts()
{
if (!s_AppAssemblyImage) return;
s_AvailableScripts.clear();
// 获取类型定义表
const MonoTableInfo *tableInfo = mono_image_get_table_info(s_AppAssemblyImage, MONO_TABLE_TYPEDEF);
int rows = mono_image_get_table_rows(s_AppAssemblyImage, MONO_TABLE_TYPEDEF);
for (int i = 0; i < rows; i++)
{
uint32_t cols[MONO_TYPEDEF_SIZE];
mono_metadata_decode_row(tableInfo, i, cols, MONO_TYPEDEF_SIZE);
// 获取类名和命名空间
const char* name = mono_metadata_string_heap(s_AppAssemblyImage, cols[MONO_TYPEDEF_NAME]);
const char* nameSpace = mono_metadata_string_heap(s_AppAssemblyImage, cols[MONO_TYPEDEF_NAMESPACE]);
if (!name || strlen(name) == 0) continue;
// 构建全名
std::string fullName;
if (nameSpace && strlen(nameSpace) > 0)
fullName = std::string(nameSpace) + "." + name;
else
fullName = name;
s_AvailableScripts.push_back(fullName);
PM_CORE_DEBUG("Script Class: {}", fullName);
}
}
const std::vector<std::string>& ScriptEngine::GetAvailableScripts()
{
return s_AvailableScripts;
}
void ScriptEngine::OnImGuiRender() void ScriptEngine::OnImGuiRender()
{ {
ImGui::Begin("Script Engine Debug"); ImGui::Begin("Script Engine Debug");

View File

@ -150,8 +150,15 @@ namespace Prism
static EntityInstanceMap& GetEntityInstanceMap(); static EntityInstanceMap& GetEntityInstanceMap();
static EntityInstanceData& GetEntityInstanceData(UUID sceneID, UUID entityID); static EntityInstanceData& GetEntityInstanceData(UUID sceneID, UUID entityID);
// GetAll Script Clas s
static const std::vector<std::string>& GetAvailableScripts();
static void RefreshAvailableScripts();
// Debug // Debug
static void OnImGuiRender(); static void OnImGuiRender();
private:
static std::vector<std::string> s_AvailableScripts;
}; };
} }

View File

@ -49,6 +49,8 @@ namespace Prism
{ {
InitComponentTypes(); InitComponentTypes();
mono_add_internal_call("Prism.Debug::Log_Native", (const void*)Prism::Script::Prism_Log_Native);
mono_add_internal_call("Prism.Noise::PerlinNoise_Native", (const void*)Prism::Script::Prism_Noise_PerlinNoise); mono_add_internal_call("Prism.Noise::PerlinNoise_Native", (const void*)Prism::Script::Prism_Noise_PerlinNoise);
mono_add_internal_call("Prism.Physics::Raycast_Native", (const void*)Prism::Script::Prism_Physics_Raycast); mono_add_internal_call("Prism.Physics::Raycast_Native", (const void*)Prism::Script::Prism_Physics_Raycast);

View File

@ -10,6 +10,7 @@
#include <mono/metadata/object.h> #include <mono/metadata/object.h>
#include <mono/metadata/reflection.h> #include <mono/metadata/reflection.h>
#include <mono/metadata/appdomain.h> #include <mono/metadata/appdomain.h>
#include <mono/utils/mono-publib.h>
#include "Prism/Core/Input.h" #include "Prism/Core/Input.h"
#include "Prism/Core/Math/Noise.h" #include "Prism/Core/Math/Noise.h"
@ -32,6 +33,31 @@ namespace Prism { namespace Script {
SpriteRenderer = 4 SpriteRenderer = 4
}; };
////////////////////////////////////////////////////////////////
// Debug ////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
static LogCallback s_LogCallback = nullptr;
void SetLogCallback(const LogCallback& callback)
{
s_LogCallback = callback;
}
void Prism_Log_Native(MonoString* message)
{
if (message)
{
if (char* utf8 = mono_string_to_utf8(message))
{
PM_CLIENT_INFO("[c#]: {}", utf8);
if (s_LogCallback) s_LogCallback(utf8);
mono_free(utf8);
}
}
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Math //////////////////////////////////////////////////////// // Math ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -385,7 +411,8 @@ namespace Prism { namespace Script {
Entity entity = entityMap.at(entityID); Entity entity = entityMap.at(entityID);
auto& transform = entity.GetComponent<TransformComponent>() = *inTransform; auto& transform = entity.GetComponent<TransformComponent>();
transform = *inTransform;
transform.Rotation = glm::radians(transform.Rotation); transform.Rotation = glm::radians(transform.Rotation);
} }
@ -454,7 +481,13 @@ namespace Prism { namespace Script {
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
Entity entity = entityMap.at(entityID); Entity entity = entityMap.at(entityID);
entity.GetComponent<TransformComponent>().Rotation = glm::radians(*inRotation); auto& transformComponent = entity.GetComponent<TransformComponent>();
transformComponent.Rotation = glm::radians(*inRotation);
const auto rotationQuat = glm::quat(transformComponent.Rotation);
transformComponent.Up = glm::normalize(glm::rotate(rotationQuat, glm::vec3(0.0f, 1.0f, 0.0f)));
transformComponent.Right = glm::normalize(glm::rotate(rotationQuat, glm::vec3(1.0f, 0.0f, 0.0f)));
transformComponent.Forward = glm::normalize(glm::rotate(rotationQuat, glm::vec3(0.0f, 0.0f, -1.0f)));
} }
void Prism_TransformComponent_GetScale(uint64_t entityID, glm::vec3* outScale) void Prism_TransformComponent_GetScale(uint64_t entityID, glm::vec3* outScale)

View File

@ -14,7 +14,11 @@ extern "C" {
typedef struct _MonoArray MonoArray; typedef struct _MonoArray MonoArray;
} }
namespace Prism { namespace Script { namespace Prism::Script
{
using LogCallback = std::function<void(const char*)>;
void SetLogCallback(const LogCallback& callback);
/* /*
struct ScriptTransform struct ScriptTransform
@ -26,6 +30,9 @@ namespace Prism { namespace Script {
}; };
*/ */
// Debug
void Prism_Log_Native(MonoString* message);
// Math // Math
float Prism_Noise_PerlinNoise(float x, float y); float Prism_Noise_PerlinNoise(float x, float y);
@ -114,7 +121,7 @@ namespace Prism { namespace Script {
void* Prism_MeshComponent_GetMesh(uint64_t entityID); void* Prism_MeshComponent_GetMesh(uint64_t entityID);
void Prism_MeshComponent_SetMesh(uint64_t entityID, const Ref<Mesh>* inMesh); void Prism_MeshComponent_SetMesh(uint64_t entityID, const Ref<Mesh>* inMesh);
} } }
#endif //SCRIPTWRAPPERS_H #endif //SCRIPTWRAPPERS_H

View File

@ -38,6 +38,8 @@ namespace Prism
static std::string OpenFileSelector(const std::string& filter = ""); static std::string OpenFileSelector(const std::string& filter = "");
static std::string SaveFileSelector(const std::string& filter = ""); static std::string SaveFileSelector(const std::string& filter = "");
static void OpenInExplorer(const std::string& path);
static bool CreateFolder(const std::filesystem::path& filepath); static bool CreateFolder(const std::filesystem::path& filepath);
static bool Exists(const std::string& filepath); static bool Exists(const std::string& filepath);
static std::string Rename(const std::string& filepath, const std::string& newName); static std::string Rename(const std::string& filepath, const std::string& newName);

View File

@ -0,0 +1,145 @@
//
// Created by Atdunbg on 2026/3/25.
//
#ifndef PRISM_SERIALIZEUTILS_H
#define PRISM_SERIALIZEUTILS_H
#include <yaml-cpp/yaml.h>
#include <glm/glm.hpp>
namespace YAML
{
template<>
struct convert<glm::vec2>
{
static Node encode(const glm::vec2& rhs)
{
Node node;
node.push_back(rhs.x);
node.push_back(rhs.y);
return node;
}
static bool decode(const Node& node, glm::vec2& rhs)
{
if (!node.IsSequence() || node.size() != 2)
return false;
rhs.x = node[0].as<float>();
rhs.y = node[1].as<float>();
return true;
}
};
template<>
struct convert<glm::vec3>
{
static Node encode(const glm::vec3& rhs)
{
Node node;
node.push_back(rhs.x);
node.push_back(rhs.y);
node.push_back(rhs.z);
return node;
}
static bool decode(const Node& node, glm::vec3& rhs)
{
if (!node.IsSequence() || node.size() != 3)
return false;
rhs.x = node[0].as<float>();
rhs.y = node[1].as<float>();
rhs.z = node[2].as<float>();
return true;
}
};
template<>
struct convert<glm::vec4>
{
static Node encode(const glm::vec4& rhs)
{
Node node;
node.push_back(rhs.x);
node.push_back(rhs.y);
node.push_back(rhs.z);
node.push_back(rhs.w);
return node;
}
static bool decode(const Node& node, glm::vec4& rhs)
{
if (!node.IsSequence() || node.size() != 4)
return false;
rhs.x = node[0].as<float>();
rhs.y = node[1].as<float>();
rhs.z = node[2].as<float>();
rhs.w = node[3].as<float>();
return true;
}
};
template<>
struct convert<glm::quat>
{
static Node encode(const glm::quat& rhs)
{
Node node;
node.push_back(rhs.w);
node.push_back(rhs.x);
node.push_back(rhs.y);
node.push_back(rhs.z);
return node;
}
static bool decode(const Node& node, glm::quat& rhs)
{
if (!node.IsSequence() || node.size() != 4)
return false;
rhs.w = node[0].as<float>();
rhs.x = node[1].as<float>();
rhs.y = node[2].as<float>();
rhs.z = node[3].as<float>();
return true;
}
};
}
namespace Prism
{
inline YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec2& v)
{
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << YAML::EndSeq;
return out;
}
inline YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec3& v)
{
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq;
return out;
}
inline YAML::Emitter& operator<<(YAML::Emitter& out, const glm::vec4& v)
{
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq;
return out;
}
inline YAML::Emitter& operator<<(YAML::Emitter& out, const glm::quat& v)
{
out << YAML::Flow;
out << YAML::BeginSeq << v.w << v.x << v.y << v.z << YAML::EndSeq;
return out;
}
}
#endif //PRISM_SERIALIZEUTILS_H

View File

@ -4,6 +4,8 @@
#include "StringUtils.h" #include "StringUtils.h"
#include <filesystem>
namespace Prism::Utils namespace Prism::Utils
{ {
@ -17,10 +19,16 @@ namespace Prism::Utils
return ""; return "";
} }
std::string ReplaceFilePathName(const std::string& filepath, const std::string& newName)
{
const std::string extension = GetExtension(filepath, true);
return std::filesystem::path(filepath).parent_path().string() + "/" + newName + extension;
}
std::string GetExtension(const std::string& filename, const bool includeDot) std::string GetExtension(const std::string& filename, const bool includeDot)
{ {
if (const std::vector<std::string> parts = SplitString(filename, '.'); parts.size() > 1) if (const std::vector<std::string> parts = SplitString(filename, '.'); parts.size() > 1)
return parts[ includeDot ? parts.size() - 1 : parts.size()]; return (includeDot ? "." : "") + parts[parts.size() - 1];
return ""; return "";
} }

View File

@ -9,8 +9,10 @@
namespace Prism::Utils namespace Prism::Utils
{ {
std::string ReplaceFilePathName(const std::string& filepath, const std::string& newName);
std::string GetFilename(const std::string& filepath); std::string GetFilename(const std::string& filepath);
std::string GetExtension(const std::string& filename, bool includeDot = true); std::string GetExtension(const std::string& filename, bool includeDot = false);
std::string RemoveExtension(const std::string& filename); std::string RemoveExtension(const std::string& filename);
std::string NormalizePath(std::string path); std::string NormalizePath(std::string path);
std::string StringToLower(const std::string& str); std::string StringToLower(const std::string& str);

View File

@ -0,0 +1,11 @@
project(PrismRuntime)
file(GLOB_RECURSE SRC_SOURCE ./PrismRuntime/**.cpp)
add_executable(${PROJECT_NAME} WIN32 ${SRC_SOURCE})
target_compile_definitions(${PROJECT_NAME} PRIVATE PRISM_GUI)
target_link_libraries(${PROJECT_NAME} PRIVATE Prism-Runtime)
add_executable(${PROJECT_NAME}-Console ${SRC_SOURCE})
target_link_libraries(${PROJECT_NAME}-Console PRIVATE Prism-Runtime)

View File

@ -0,0 +1,90 @@
//
// Created by Atdunbg on 2026/3/23.
//
#include "PrismRuntime.h"
#include "Prism/Core/Input.h"
#include "Prism/Renderer/Renderer.h"
#include "Prism/Renderer/SceneRenderer.h"
#include "Prism/Scene/SceneSerializer.h"
void PrismRuntime::OnAttach()
{
PM_CLIENT_INFO("App init");
AppInstance = &Prism::Application::Get();
sceneName.emplace_back("assets/scenes/FPS.scene");
sceneName.emplace_back("assets/scenes/FPSdemo.scene");
LoadScene(sceneName[0]);
}
void PrismRuntime::OnDetach()
{
PM_CLIENT_INFO("Scene Shutdown");
m_CurrentScene->OnShutdown();
}
void PrismRuntime::LoadScene(const std::string& scene)
{
if (m_CurrentScene)
{
PM_CLIENT_INFO("Scene Shutdown");
m_CurrentScene->OnShutdown();
}
const Prism::Ref<Prism::Scene> newScene = Prism::Ref<Prism::Scene>::Create("runtime Scene", false, true);
Prism::SceneSerializer serializer(newScene);
PM_CLIENT_INFO("loading Scene: ", scene);
serializer.Deserialize(scene);
m_CurrentScene = newScene;
const glm::ivec2 windowSize = AppInstance->GetWindow().GetSize();
if (m_CurrentScene && windowSize.x > 0 && windowSize.y > 0)
{
Prism::SceneRenderer::SetViewportSize(windowSize.x, windowSize.y);
m_CurrentScene->SetViewportSize(windowSize);
}
m_CurrentScene->OnRuntimeStart();
}
void PrismRuntime::OnUpdate(const Prism::TimeStep deltaTime)
{
m_CurrentScene->OnUpdate(deltaTime);
m_CurrentScene->OnRenderRuntime(deltaTime);
const glm::vec2 windowSize = AppInstance->GetWindow().GetSize();
if (m_CurrentScene && windowSize.x > 0 && windowSize.y > 0)
{
m_CurrentScene->SetViewportSize(windowSize);
}
if (shouldChangeScene)
{
LoadScene(sceneName[nextScene]);
shouldChangeScene = false;
}
}
void PrismRuntime::OnEvent(Prism::Event& e)
{
if (Prism::Input::IsKeyPressed(Prism::KeyCode::L) && nextScene == 0)
{
shouldChangeScene = true;
nextScene++;
} else if (Prism::Input::IsKeyPressed(Prism::KeyCode::K) && nextScene == 1)
{
shouldChangeScene = true;
nextScene--;
}
}
void PrismRuntime::OnImGuiRender()
{
}

View File

@ -0,0 +1,38 @@
//
// Created by Atdunbg on 2026/3/23.
//
#ifndef PRISM_PRISMRUNTIME_H
#define PRISM_PRISMRUNTIME_H
#include "Prism/Core/Application.h"
#include "Prism/Core/Layer.h"
#include "Prism/Scene/Scene.h"
class PrismRuntime : public Prism::Layer
{
public:
void OnAttach() override;
void OnDetach() override;
void LoadScene(const std::string& scene);
void OnUpdate(Prism::TimeStep deltaTime) override;
void OnEvent(Prism::Event& e) override;
void OnImGuiRender() override;
private:
Prism::Ref<Prism::Scene> m_CurrentScene;
Prism::Application* AppInstance = nullptr;
bool shouldChangeScene = false;
// debug
std::vector<std::string> sceneName;
int nextScene = 0;
};
#endif //PRISM_PRISMRUNTIME_H

View File

@ -0,0 +1,25 @@
//
// Created by Atdunbg on 2026/3/23.
//
#include "Prism.h"
#include "PrismRuntime.h"
#include "Prism/Core/EntryPoint.h"
class PrismRuntimeApp : public Prism::Application
{
public:
explicit PrismRuntimeApp(const Prism::ApplicationProps& props)
: Application(props)
{
}
virtual void OnInit() override
{
PushLayer(new PrismRuntime());
}
};
Prism::Application* Prism::CreateApplication(const CommandArgs args)
{
return new PrismRuntimeApp({"Game", 1920, 1080, args});
}