Compare commits
1 Commits
forward-re
...
mono
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b82b30de1 |
9
.gitmodules
vendored
@ -26,12 +26,3 @@
|
|||||||
[submodule "Prism/vendor/Box2D"]
|
[submodule "Prism/vendor/Box2D"]
|
||||||
path = Prism/vendor/Box2D
|
path = Prism/vendor/Box2D
|
||||||
url = https://github.com/erincatto/box2d.git
|
url = https://github.com/erincatto/box2d.git
|
||||||
[submodule "Prism/vendor/PhysX"]
|
|
||||||
path = Prism/vendor/PhysX
|
|
||||||
url = https://github.com/NVIDIA-Omniverse/PhysX.git
|
|
||||||
[submodule "Prism/vendor/ImViewGuizmo"]
|
|
||||||
path = Prism/vendor/ImViewGuizmo
|
|
||||||
url = https://github.com/Ka1serM/ImViewGuizmo
|
|
||||||
[submodule "Prism/vendor/efsw"]
|
|
||||||
path = Prism/vendor/efsw
|
|
||||||
url = https://github.com/SpartanJ/efsw
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
|||||||
# set MSVC output directory
|
# set MSVC output directory
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# config
|
# config
|
||||||
string(REPLACE "/showIncludes" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
|
||||||
# temp config
|
# temp config
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251")
|
||||||
|
|
||||||
@ -23,5 +23,4 @@ endif ()
|
|||||||
|
|
||||||
add_subdirectory(Prism)
|
add_subdirectory(Prism)
|
||||||
add_subdirectory(Sandbox)
|
add_subdirectory(Sandbox)
|
||||||
add_subdirectory(Editor)
|
add_subdirectory(Editor)
|
||||||
add_subdirectory(PrismRuntime)
|
|
||||||
@ -2,21 +2,17 @@ project(PrismEditor)
|
|||||||
|
|
||||||
set(CMAKE_BINARY_DIR ${CMAKE_BINARY_DIR}/bin)
|
set(CMAKE_BINARY_DIR ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
file(GLOB ASSETS "assets")
|
file(GLOB ASSETS assets)
|
||||||
file(COPY ${ASSETS} DESTINATION ${CMAKE_BINARY_DIR})
|
file(COPY ${ASSETS} DESTINATION ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
# imgui.ini file
|
|
||||||
file(GLOB IMGUI_INI imgui.ini)
|
|
||||||
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 ./Editor/**.cpp)
|
file(GLOB_RECURSE SRC_SOURCE ./**.cpp)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SRC_SOURCE})
|
add_executable(${PROJECT_NAME} ${SRC_SOURCE})
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Prism-static)
|
target_link_libraries(${PROJECT_NAME} PRIVATE Prism-shared)
|
||||||
|
|
||||||
# Enable ImGui Docking space
|
# Enable ImGui Docking space
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_DOCKSPACE)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_DOCKSPACE)
|
||||||
|
|||||||
@ -23,7 +23,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Prism::Application* Prism::CreateApplication(const CommandArgs args)
|
Prism::Application* Prism::CreateApplication()
|
||||||
{
|
{
|
||||||
return new Editor({"hello world", 1920, 1080, args});
|
return new Editor({"hello wrold", 1920, 1080});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,10 +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/ObjectsPanel.h"
|
|
||||||
#include "Prism/Editor/SceneHierachyPanel.h"
|
#include "Prism/Editor/SceneHierachyPanel.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -29,7 +26,7 @@ namespace Prism
|
|||||||
bool OnKeyPressedEvent(KeyPressedEvent& e);
|
bool OnKeyPressedEvent(KeyPressedEvent& e);
|
||||||
bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
|
bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
|
||||||
|
|
||||||
void ShowBoundingBoxes(bool show);
|
void ShowBoundingBoxes(bool show, bool onTop = false);
|
||||||
void SelectEntity(Entity entity);
|
void SelectEntity(Entity entity);
|
||||||
|
|
||||||
void UpdateWindowTitle(const std::string& sceneName);
|
void UpdateWindowTitle(const std::string& sceneName);
|
||||||
@ -47,22 +44,18 @@ namespace Prism
|
|||||||
void OnEntityDeleted(Entity e);
|
void OnEntityDeleted(Entity e);
|
||||||
Ray CastMouseRay();
|
Ray CastMouseRay();
|
||||||
|
|
||||||
void NewScene();
|
|
||||||
void OpenScene();
|
void OpenScene();
|
||||||
void OpenScene(const std::string& filepath);
|
|
||||||
void SaveScene();
|
void SaveScene();
|
||||||
void SaveSceneAs();
|
void SaveSceneAs();
|
||||||
|
|
||||||
void OnScenePlay();
|
void OnScenePlay();
|
||||||
void OnSceneStop();
|
void OnSceneStop();
|
||||||
|
|
||||||
float GetSnapValue() const;
|
float GetSnapValue();
|
||||||
private:
|
private:
|
||||||
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
|
Scope<SceneHierarchyPanel> m_SceneHierarchyPanel;
|
||||||
Scope<ContentBrowserPanel> m_ContentBrowserPanel;
|
|
||||||
Scope<ObjectsPanel> m_ObjectsPanel;
|
|
||||||
|
|
||||||
Ref<Scene> m_CurrentScene;
|
Ref<Scene> m_ActiveScene;
|
||||||
Ref<Scene> m_RuntimeScene, m_EditorScene;
|
Ref<Scene> m_RuntimeScene, m_EditorScene;
|
||||||
std::string m_SceneFilePath;
|
std::string m_SceneFilePath;
|
||||||
|
|
||||||
@ -119,7 +112,7 @@ namespace Prism
|
|||||||
|
|
||||||
struct RoughnessInput
|
struct RoughnessInput
|
||||||
{
|
{
|
||||||
float Value = 1.0f;
|
float Value = 0.5f;
|
||||||
Ref<Texture2D> TextureMap;
|
Ref<Texture2D> TextureMap;
|
||||||
bool UseTexture = false;
|
bool UseTexture = false;
|
||||||
};
|
};
|
||||||
@ -127,14 +120,22 @@ namespace Prism
|
|||||||
|
|
||||||
|
|
||||||
// PBR params
|
// PBR params
|
||||||
|
bool m_RadiancePrefilter = false;
|
||||||
|
|
||||||
|
float m_EnvMapRotation = 0.0f;
|
||||||
|
|
||||||
|
|
||||||
// Editor resources
|
// Editor resources
|
||||||
Ref<Texture2D> m_CheckerboardTex;
|
Ref<Texture2D> m_CheckerboardTex;
|
||||||
Ref<Texture2D> m_PlayButtonTex, m_StopButtonTex, m_PauseButtonTex;
|
Ref<Texture2D> m_PlayButtonTex;
|
||||||
|
|
||||||
|
|
||||||
|
// configure button
|
||||||
|
bool m_AllowViewportCameraEvents = false;
|
||||||
|
bool m_DrawOnTopBoundingBoxes = false;
|
||||||
|
|
||||||
bool m_UIShowBoundingBoxes = false;
|
bool m_UIShowBoundingBoxes = false;
|
||||||
|
bool m_UIShowBoundingBoxesOnTop = false;
|
||||||
|
|
||||||
enum class SceneType : uint32_t
|
enum class SceneType : uint32_t
|
||||||
{
|
{
|
||||||
@ -142,18 +143,14 @@ namespace Prism
|
|||||||
};
|
};
|
||||||
SceneType m_SceneType;
|
SceneType m_SceneType;
|
||||||
|
|
||||||
bool m_ViewportPanelHovered = false;
|
bool m_ViewportPanelMouseOver = false;
|
||||||
bool m_ViewportPanelFocused = false;
|
bool m_ViewportPanelFocused = false;
|
||||||
bool m_ShowPhysicsSettings = false;
|
|
||||||
|
|
||||||
enum class SceneState
|
enum class SceneState
|
||||||
{
|
{
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,66 +0,0 @@
|
|||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 119 B |
|
Before Width: | Height: | Size: 115 B |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 12 KiB |
155
Editor/assets/scenes/2DTest.scene
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
Scene: Scene Name
|
||||||
|
Environment:
|
||||||
|
AssetPath: assets/env/pink_sunrise_4k.hdr
|
||||||
|
Light:
|
||||||
|
Direction: [-0.787, -0.73299998, 1]
|
||||||
|
Radiance: [1, 1, 1]
|
||||||
|
Multiplier: 0.514999986
|
||||||
|
Entities:
|
||||||
|
- Entity: 12498244675852797835
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-12.0348625, 6.59647179, 9.60061925e-07]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [3.00000024, 0.300000012, 1]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 0
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [1.5, 0.150000006]
|
||||||
|
Density: 1
|
||||||
|
Friction: 1
|
||||||
|
- Entity: 5178862374589434728
|
||||||
|
TagComponent:
|
||||||
|
Tag: Camera
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-21.7406311, 9.70659542, 15]
|
||||||
|
Rotation: [0.999910355, -0.0133911213, 0, 0]
|
||||||
|
Scale: [1, 1, 1]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.BasicController
|
||||||
|
StoredFields:
|
||||||
|
- Name: Speed
|
||||||
|
Type: 1
|
||||||
|
Data: 12
|
||||||
|
CameraComponent:
|
||||||
|
Camera: some camera data...
|
||||||
|
Primary: true
|
||||||
|
- Entity: 1289165777996378215
|
||||||
|
TagComponent:
|
||||||
|
Tag: Cube
|
||||||
|
TransformComponent:
|
||||||
|
Position: [500, 0, 0]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [1200, 1, 5]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 0
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [600, 0.5]
|
||||||
|
Density: 1
|
||||||
|
Friction: 2
|
||||||
|
- Entity: 14057422478420564497
|
||||||
|
TagComponent:
|
||||||
|
Tag: Player
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-23.6932545, 1.59184527, -1.96369365e-06]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [1, 1, 1]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.PlayerCube
|
||||||
|
StoredFields:
|
||||||
|
- Name: HorizontalForce
|
||||||
|
Type: 1
|
||||||
|
Data: 0.5
|
||||||
|
- Name: MaxSpeed
|
||||||
|
Type: 5
|
||||||
|
Data: [7, 10]
|
||||||
|
- Name: JumpForce
|
||||||
|
Type: 1
|
||||||
|
Data: 3
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Sphere1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 29.2000008
|
||||||
|
CircleCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Radius: 0.5
|
||||||
|
Density: 1
|
||||||
|
Friction: 1
|
||||||
|
- Entity: 1352995477042327524
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-29.6808929, 29.7597198, 0]
|
||||||
|
Rotation: [0.707106769, 0, 0, 0.707106769]
|
||||||
|
Scale: [58.4179001, 4.47999144, 4.48000002]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 0
|
||||||
|
Mass: 3
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [29.7000008, 2.24000001]
|
||||||
|
Density: 1
|
||||||
|
Friction: 1
|
||||||
|
- Entity: 15223077898852293773
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [6.12674046, 45.5617676, 0]
|
||||||
|
Rotation: [0.977883637, 0, 0, -0.209149584]
|
||||||
|
Scale: [4.47999668, 4.47999668, 4.48000002]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [2.24000001, 2.24000001]
|
||||||
|
Density: 1
|
||||||
|
Friction: 1
|
||||||
|
- Entity: 5421735812495444456
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-20.766222, 2.29431438, 0]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [3.00000024, 0.300000012, 1]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 0
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [1.5, 0.150000006]
|
||||||
|
Density: 1
|
||||||
|
Friction: 1
|
||||||
|
- Entity: 2842299641876190180
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-16.6143265, 4.39151001, 6.43359499e-09]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [3.00000024, 0.300000012, 1]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 0
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [1.5, 0.150000006]
|
||||||
|
Density: 1
|
||||||
|
Friction: 1
|
||||||
@ -1,336 +0,0 @@
|
|||||||
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:
|
|
||||||
[]
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
Scene: Scene Name
|
|
||||||
Environment:
|
|
||||||
AssetHandle: 6095149963749185931
|
|
||||||
Entities:
|
|
||||||
- Entity: 6421668200759325475
|
|
||||||
Parent: 0
|
|
||||||
Children:
|
|
||||||
[]
|
|
||||||
TagComponent:
|
|
||||||
Tag: M1911Materials
|
|
||||||
TransformComponent:
|
|
||||||
Position: [0, 3.159583, 0]
|
|
||||||
Rotation: [0, 0, 0]
|
|
||||||
Scale: [1, 1, 1]
|
|
||||||
MeshComponent:
|
|
||||||
AssetID: 7219694555758922702
|
|
||||||
AssetPath: assets/models/m1911/M1911Materials.fbx
|
|
||||||
- Entity: 16992665426857995732
|
|
||||||
Parent: 0
|
|
||||||
Children:
|
|
||||||
[]
|
|
||||||
TagComponent:
|
|
||||||
Tag: Cube
|
|
||||||
TransformComponent:
|
|
||||||
Position: [0, 0, 0]
|
|
||||||
Rotation: [0, 0, 0]
|
|
||||||
Scale: [50, 1, 50]
|
|
||||||
MeshComponent:
|
|
||||||
AssetID: 18328012085543462741
|
|
||||||
AssetPath: assets/meshes/Default/Cube.fbx
|
|
||||||
- Entity: 18182275256052989728
|
|
||||||
Parent: 0
|
|
||||||
Children:
|
|
||||||
[]
|
|
||||||
TagComponent:
|
|
||||||
Tag: Sky Light
|
|
||||||
TransformComponent:
|
|
||||||
Position: [0, 0, 0]
|
|
||||||
Rotation: [0, 0, 0]
|
|
||||||
Scale: [1, 1, 1]
|
|
||||||
SkyLightComponent:
|
|
||||||
EnvironmentMap: 6095149963749185931
|
|
||||||
EnvironmentAssetPath: ""
|
|
||||||
Intensity: 1
|
|
||||||
Angle: 0
|
|
||||||
DynamicSky: true
|
|
||||||
TurbidityAzimuthInclination: [2, 0.15, 0.71]
|
|
||||||
- Entity: 17803125207910630398
|
|
||||||
Parent: 0
|
|
||||||
Children:
|
|
||||||
[]
|
|
||||||
TagComponent:
|
|
||||||
Tag: Directional Light
|
|
||||||
TransformComponent:
|
|
||||||
Position: [0, 0, 0]
|
|
||||||
Rotation: [-0.4810984, -0.20606127, 2.9545484]
|
|
||||||
Scale: [1.0000023, 1.0000007, 0.9999998]
|
|
||||||
DirectionalLightComponent:
|
|
||||||
Radiance: [1, 1, 1]
|
|
||||||
CastShadows: true
|
|
||||||
SoftShadows: true
|
|
||||||
LightSize: 0.9
|
|
||||||
PhysicsLayers:
|
|
||||||
[]
|
|
||||||
174
Editor/assets/scenes/Physics2DTest.hsc
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
Scene: Scene Name
|
||||||
|
Environment:
|
||||||
|
AssetPath: assets/env/pink_sunrise_4k.hdr
|
||||||
|
Light:
|
||||||
|
Direction: [-0.787, -0.73299998, 1]
|
||||||
|
Radiance: [1, 1, 1]
|
||||||
|
Multiplier: 0.514999986
|
||||||
|
Entities:
|
||||||
|
- Entity: 15861629587505754
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-18.2095661, 39.2518234, 0]
|
||||||
|
Rotation: [0.967056513, 0, 0, -0.254561812]
|
||||||
|
Scale: [4.47999525, 4.47999525, 4.48000002]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [2.24000001, 2.24000001]
|
||||||
|
- Entity: 15223077898852293773
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [5.37119865, 43.8762894, 0]
|
||||||
|
Rotation: [0.977883637, 0, 0, -0.209149718]
|
||||||
|
Scale: [4.47999668, 4.47999668, 4.48000002]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [2.24000001, 2.24000001]
|
||||||
|
- Entity: 2157107598622182863
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-7.60411549, 44.1442184, 0]
|
||||||
|
Rotation: [0.989285827, 0, 0, 0.145991713]
|
||||||
|
Scale: [4.47999287, 4.47999287, 4.48000002]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 0.5
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [2.24000001, 2.24000001]
|
||||||
|
- Entity: 8080964283681139153
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-0.739211679, 37.7653275, 0]
|
||||||
|
Rotation: [0.956475914, 0, 0, -0.291811317]
|
||||||
|
Scale: [5, 2, 2]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 0.25
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [2.5, 1]
|
||||||
|
- Entity: 1352995477042327524
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-8.32969856, 30.4078159, 0]
|
||||||
|
Rotation: [0.781595349, 0, 0, 0.623785794]
|
||||||
|
Scale: [14.000001, 4.47999334, 4.48000002]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 3
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [7, 2.24000001]
|
||||||
|
- Entity: 935615878363259513
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [6.88031197, 31.942337, 0]
|
||||||
|
Rotation: [0.986578286, 0, 0, 0.163288936]
|
||||||
|
Scale: [4.47999954, 4.47999954, 4.48000002]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [2.24000001, 2.24000001]
|
||||||
|
- Entity: 14057422478420564497
|
||||||
|
TagComponent:
|
||||||
|
Tag: Player
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0, 22.774044, 0]
|
||||||
|
Rotation: [0.942591429, 0, 0, -0.333948225]
|
||||||
|
Scale: [6.00000048, 6.00000048, 4.48000002]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.PlayerCube
|
||||||
|
StoredFields:
|
||||||
|
- Name: HorizontalForce
|
||||||
|
Type: 1
|
||||||
|
Data: 10
|
||||||
|
- Name: VerticalForce
|
||||||
|
Type: 1
|
||||||
|
Data: 10
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Sphere1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 1
|
||||||
|
CircleCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Radius: 3
|
||||||
|
- Entity: 1289165777996378215
|
||||||
|
TagComponent:
|
||||||
|
Tag: Cube
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0, 0, 0]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [50, 1, 50]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.Sink
|
||||||
|
StoredFields:
|
||||||
|
- Name: SinkSpeed
|
||||||
|
Type: 1
|
||||||
|
Data: 0
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 0
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [25, 0.5]
|
||||||
|
- Entity: 5178862374589434728
|
||||||
|
TagComponent:
|
||||||
|
Tag: Camera
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0, 25, 79.75]
|
||||||
|
Rotation: [0.995602965, -0.0936739072, 0, 0]
|
||||||
|
Scale: [1, 0.999999821, 0.999999821]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.BasicController
|
||||||
|
StoredFields:
|
||||||
|
- Name: Speed
|
||||||
|
Type: 1
|
||||||
|
Data: 12
|
||||||
|
CameraComponent:
|
||||||
|
Camera: some camera data...
|
||||||
|
Primary: true
|
||||||
|
- Entity: 3948844418381294888
|
||||||
|
TagComponent:
|
||||||
|
Tag: Box
|
||||||
|
TransformComponent:
|
||||||
|
Position: [-1.48028564, 49.5945244, -2.38418579e-07]
|
||||||
|
Rotation: [0.977883637, 0, 0, -0.209149733]
|
||||||
|
Scale: [1.99999976, 1.99999976, 2]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Cube1m.fbx
|
||||||
|
RigidBody2DComponent:
|
||||||
|
BodyType: 1
|
||||||
|
Mass: 1
|
||||||
|
BoxCollider2DComponent:
|
||||||
|
Offset: [0, 0]
|
||||||
|
Size: [1, 1]
|
||||||
66
Editor/assets/scenes/PinkSunrise.hsc
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
Scene: Scene Name
|
||||||
|
Environment:
|
||||||
|
AssetPath: assets/env/birchwood_4k.hdr
|
||||||
|
Light:
|
||||||
|
Direction: [-0.5, -0.5, 1]
|
||||||
|
Radiance: [1, 1, 1]
|
||||||
|
Multiplier: 1
|
||||||
|
Entities:
|
||||||
|
- Entity: 1289165777996378215
|
||||||
|
TagComponent:
|
||||||
|
Tag: Sphere
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0, 21.9805069, -1.64006281]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [0.100000024, 0.100000024, 0.100000024]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.Sink
|
||||||
|
StoredFields:
|
||||||
|
- Name: SinkSpeed
|
||||||
|
Type: 1
|
||||||
|
Data: 5
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/Sphere1m.fbx
|
||||||
|
- Entity: 5178862374589434728
|
||||||
|
TagComponent:
|
||||||
|
Tag: Camera
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0, 14.75, 79.75]
|
||||||
|
Rotation: [0.995602965, -0.0936739072, 0, 0]
|
||||||
|
Scale: [1, 0.999999821, 0.999999821]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.BasicController
|
||||||
|
StoredFields:
|
||||||
|
- Name: Speed
|
||||||
|
Type: 1
|
||||||
|
Data: 12
|
||||||
|
CameraComponent:
|
||||||
|
Camera: some camera data...
|
||||||
|
Primary: true
|
||||||
|
- Entity: 9095450049242347594
|
||||||
|
TagComponent:
|
||||||
|
Tag: Test Entity
|
||||||
|
TransformComponent:
|
||||||
|
Position: [0.248109579, -1.90734863e-06, -0.268640995]
|
||||||
|
Rotation: [1, 0, 0, 0]
|
||||||
|
Scale: [1, 1, 1]
|
||||||
|
ScriptComponent:
|
||||||
|
ModuleName: Example.Script
|
||||||
|
StoredFields:
|
||||||
|
- Name: VerticalSpeed
|
||||||
|
Type: 1
|
||||||
|
Data: 0
|
||||||
|
- Name: SinkRate
|
||||||
|
Type: 1
|
||||||
|
Data: 0
|
||||||
|
- Name: Speed
|
||||||
|
Type: 1
|
||||||
|
Data: 1
|
||||||
|
- Name: Rotation
|
||||||
|
Type: 1
|
||||||
|
Data: 0
|
||||||
|
- Name: Velocity
|
||||||
|
Type: 6
|
||||||
|
Data: [0, 0, 0]
|
||||||
|
MeshComponent:
|
||||||
|
AssetPath: assets/meshes/TestScene.fbx
|
||||||
@ -1,36 +0,0 @@
|
|||||||
Scene: Scene Name
|
|
||||||
Environment:
|
|
||||||
AssetHandle: 5211537204242875091
|
|
||||||
Entities:
|
|
||||||
- Entity: 15706224176559717512
|
|
||||||
Parent: 0
|
|
||||||
Children:
|
|
||||||
[]
|
|
||||||
TagComponent:
|
|
||||||
Tag: Cube
|
|
||||||
TransformComponent:
|
|
||||||
Position: [0, 0, 0]
|
|
||||||
Rotation: [0, 0, 0]
|
|
||||||
Scale: [1, 1, 1]
|
|
||||||
MeshComponent:
|
|
||||||
AssetID: 18328012085543462741
|
|
||||||
AssetPath: assets/meshes/Default/Cube.fbx
|
|
||||||
- Entity: 8041206185299282567
|
|
||||||
Parent: 0
|
|
||||||
Children:
|
|
||||||
[]
|
|
||||||
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:
|
|
||||||
[]
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
#type vertex
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
|
||||||
layout(location = 1) in vec2 a_TexCoord;
|
|
||||||
|
|
||||||
out vec2 v_TexCoord;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 position = vec4(a_Position.xy, 0.0, 1.0);
|
|
||||||
v_TexCoord = a_TexCoord;
|
|
||||||
gl_Position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
#type fragment
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Color;
|
|
||||||
|
|
||||||
in vec2 v_TexCoord;
|
|
||||||
|
|
||||||
uniform sampler2D u_SceneTexture;
|
|
||||||
uniform sampler2D u_BloomTexture;
|
|
||||||
|
|
||||||
uniform float u_Exposure;
|
|
||||||
uniform bool u_EnableBloom;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
const float gamma = 2.2;
|
|
||||||
const float pureWhite = 1.0;
|
|
||||||
|
|
||||||
// Tonemapping
|
|
||||||
vec3 color = texture(u_SceneTexture, v_TexCoord).rgb;
|
|
||||||
if (u_EnableBloom)
|
|
||||||
{
|
|
||||||
vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
|
|
||||||
color += bloomColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reinhard tonemapping
|
|
||||||
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
|
|
||||||
float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance);
|
|
||||||
|
|
||||||
// Scale color by ratio of average luminances.
|
|
||||||
vec3 mappedColor = (mappedLuminance / luminance) * color* u_Exposure;
|
|
||||||
|
|
||||||
// Gamma correction.
|
|
||||||
o_Color = vec4(mappedColor, 1.0);
|
|
||||||
#else
|
|
||||||
const float gamma = 2.2;
|
|
||||||
vec3 hdrColor = texture(u_SceneTexture, v_TexCoord).rgb;
|
|
||||||
vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
|
|
||||||
hdrColor += bloomColor; // additive blending
|
|
||||||
// tone mapping
|
|
||||||
vec3 result = vec3(1.0) - exp(-hdrColor * u_Exposure);
|
|
||||||
// also gamma correct while we're at it
|
|
||||||
result = pow(result, vec3(1.0 / gamma));
|
|
||||||
o_Color = vec4(result, 1.0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
@ -1,84 +0,0 @@
|
|||||||
#type vertex
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
|
||||||
layout(location = 1) in vec2 a_TexCoord;
|
|
||||||
|
|
||||||
out vec2 v_TexCoord;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec4 position = vec4(a_Position.xy, 0.0, 1.0);
|
|
||||||
v_TexCoord = a_TexCoord;
|
|
||||||
gl_Position = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
#type fragment
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Color;
|
|
||||||
|
|
||||||
in vec2 v_TexCoord;
|
|
||||||
|
|
||||||
uniform sampler2D u_Texture;
|
|
||||||
uniform bool u_Horizontal; // 未使用,可保留或移除
|
|
||||||
uniform bool u_FirstPass; // 是否进行阈值处理
|
|
||||||
uniform float u_Threshold; // 亮度阈值
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
float Pi = 6.28318530718; // 2*PI
|
|
||||||
|
|
||||||
float Directions = 32.0; // 模糊方向数
|
|
||||||
float Quality = 6.0; // 每个方向上的采样质量(采样次数)
|
|
||||||
float Size = 16.0; // 模糊半径
|
|
||||||
|
|
||||||
vec2 Radius = Size / textureSize(u_Texture, 0);
|
|
||||||
|
|
||||||
// 中心像素采样
|
|
||||||
vec3 centerColor = texture(u_Texture, v_TexCoord).rgb;
|
|
||||||
float centerLum = dot(centerColor, vec3(0.2126, 0.7152, 0.0722));
|
|
||||||
|
|
||||||
// 如果启用第一次处理且中心像素亮度低于阈值,则直接输出黑色(不进行模糊)
|
|
||||||
if (u_FirstPass && centerLum <= u_Threshold)
|
|
||||||
{
|
|
||||||
o_Color = vec4(0.0, 0.0, 0.0, 1.0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 result = centerColor; // 先累加中心像素
|
|
||||||
float totalSamples = 1.0; // 有效采样计数(中心像素已计入)
|
|
||||||
|
|
||||||
// 周围像素采样
|
|
||||||
for (float d = 0.0; d < Pi; d += Pi / Directions)
|
|
||||||
{
|
|
||||||
for (float i = 1.0 / Quality; i <= 1.0; i += 1.0 / Quality)
|
|
||||||
{
|
|
||||||
vec2 offset = vec2(cos(d), sin(d)) * Radius * i;
|
|
||||||
vec3 sampleColor = texture(u_Texture, v_TexCoord + offset).rgb;
|
|
||||||
|
|
||||||
if (u_FirstPass)
|
|
||||||
{
|
|
||||||
float lum = dot(sampleColor, vec3(0.2126, 0.7152, 0.0722));
|
|
||||||
if (lum <= u_Threshold)
|
|
||||||
{
|
|
||||||
// 低于阈值则贡献黑色,但采样点仍计入分母?这里选择不计入有效采样数
|
|
||||||
// 若希望保持模糊能量,可以 continue 跳过累加,但需调整分母
|
|
||||||
// 为简单起见,此处设为黑色并计入计数(分母不变),也可选择跳过
|
|
||||||
sampleColor = vec3(0.0);
|
|
||||||
// 如果希望忽略该采样点,可以 continue 并减少 totalSamples
|
|
||||||
// 但为了效果平滑,这里保留为黑色并计入计数
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result += sampleColor;
|
|
||||||
totalSamples += 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 归一化:除以总采样数(包括中心像素)
|
|
||||||
// 若之前选择忽略低于阈值的采样点(continue),则需相应调整 totalSamples
|
|
||||||
result /= totalSamples;
|
|
||||||
|
|
||||||
o_Color = vec4(result, 1.0);
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
// Collider Shader
|
|
||||||
|
|
||||||
#type vertex
|
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
|
||||||
|
|
||||||
uniform mat4 u_ViewProjection;
|
|
||||||
uniform mat4 u_Transform;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#type fragment
|
|
||||||
#version 450
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
color = vec4(0.1, 1.0, 0.1, 1.0);
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
#type compute
|
|
||||||
#version 460 core
|
|
||||||
layout(local_size_x = 1, local_size_y = 1) in;
|
|
||||||
|
|
||||||
layout(binding = 0, std430) buffer Histogram {
|
|
||||||
uint bins[64];
|
|
||||||
};
|
|
||||||
layout(binding = 1, std430) buffer Exposure {
|
|
||||||
float exposure;
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform float u_SpeedUp;
|
|
||||||
uniform float u_SpeedDown;
|
|
||||||
uniform float u_Key;
|
|
||||||
uniform float u_LowPercent;
|
|
||||||
uniform float u_HighPercent;
|
|
||||||
uniform float u_MinExposure;
|
|
||||||
uniform float u_MaxExposure;
|
|
||||||
uniform float u_DeltaTime;
|
|
||||||
uniform float u_LogMin;
|
|
||||||
uniform float u_LogMax;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
float currentExposure = exposure;
|
|
||||||
|
|
||||||
uint total = 0;
|
|
||||||
uint prefix[64];
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
total += bins[i];
|
|
||||||
prefix[i] = total;
|
|
||||||
}
|
|
||||||
|
|
||||||
float lowCount = u_LowPercent * 0.01 * total;
|
|
||||||
float highCount = u_HighPercent * 0.01 * total;
|
|
||||||
int lowBin = 0, highBin = 63;
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
if (prefix[i] < lowCount) lowBin = i + 1;
|
|
||||||
if (prefix[i] < highCount) highBin = i + 1;
|
|
||||||
}
|
|
||||||
lowBin = clamp(lowBin, 0, 63);
|
|
||||||
highBin = clamp(highBin, 0, 63);
|
|
||||||
|
|
||||||
float sumLum = 0.0;
|
|
||||||
uint count = 0;
|
|
||||||
for (int i = lowBin; i <= highBin; i++) {
|
|
||||||
float t = (float(i) + 0.5) / 64.0;
|
|
||||||
float logLum = u_LogMin + t * (u_LogMax - u_LogMin);
|
|
||||||
float lum = exp2(logLum);
|
|
||||||
sumLum += lum * float(bins[i]);
|
|
||||||
count += bins[i];
|
|
||||||
}
|
|
||||||
float avgLum = count > 0 ? sumLum / count : 0.18;
|
|
||||||
|
|
||||||
float targetExposure = u_Key / max(avgLum, 0.0001);
|
|
||||||
targetExposure = clamp(targetExposure, u_MinExposure, u_MaxExposure);
|
|
||||||
|
|
||||||
float speed = (targetExposure > currentExposure) ? u_SpeedUp : u_SpeedDown;
|
|
||||||
float adaptFactor = 1.0 - exp(-speed * u_DeltaTime);
|
|
||||||
float newExposure = mix(currentExposure, targetExposure, adaptFactor);
|
|
||||||
newExposure = clamp(newExposure, u_MinExposure, u_MaxExposure);
|
|
||||||
|
|
||||||
exposure = newExposure;
|
|
||||||
}
|
|
||||||
45
Editor/assets/shaders/Grid.glsl
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Grid Shader
|
||||||
|
|
||||||
|
#type vertex
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 1) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
uniform mat4 u_ViewProjection;
|
||||||
|
uniform mat4 u_Transform;
|
||||||
|
|
||||||
|
out vec2 v_TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
|
||||||
|
gl_Position = position;
|
||||||
|
|
||||||
|
v_TexCoord = a_TexCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 color;
|
||||||
|
|
||||||
|
uniform float u_Scale;
|
||||||
|
uniform float u_Res;
|
||||||
|
|
||||||
|
in vec2 v_TexCoord;
|
||||||
|
|
||||||
|
float grid(vec2 st, float res)
|
||||||
|
{
|
||||||
|
vec2 grid = fract(st);
|
||||||
|
return step(res, grid.x) * step(res, grid.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float scale = u_Scale;
|
||||||
|
float resolution = u_Res;
|
||||||
|
|
||||||
|
float x = grid(v_TexCoord * scale, resolution);
|
||||||
|
color = vec4(vec3(0.2), 0.5) * (1.0 - x);
|
||||||
|
}
|
||||||
@ -1,26 +0,0 @@
|
|||||||
#type compute
|
|
||||||
#version 460 core
|
|
||||||
layout(local_size_x = 16, local_size_y = 16) in;
|
|
||||||
|
|
||||||
layout(binding = 0) uniform sampler2D u_SceneColor;
|
|
||||||
layout(binding = 1, std430) buffer Histogram {
|
|
||||||
uint bins[64];
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform float u_LogMin;
|
|
||||||
uniform float u_LogMax;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
|
||||||
ivec2 size = textureSize(u_SceneColor, 0);
|
|
||||||
if (texel.x >= size.x || texel.y >= size.y) return;
|
|
||||||
|
|
||||||
vec3 color = texelFetch(u_SceneColor, texel, 0).rgb;
|
|
||||||
float lum = max(dot(color, vec3(0.2126, 0.7152, 0.0722)), 0.0001);
|
|
||||||
float logLum = log2(lum);
|
|
||||||
|
|
||||||
float invLogRange = 1.0 / (u_LogMax - u_LogMin);
|
|
||||||
float t = (logLum - u_LogMin) * invLogRange;
|
|
||||||
int bin = int(clamp(t * 64.0, 0.0, 63.0));
|
|
||||||
atomicAdd(bins[bin], 1u);
|
|
||||||
}
|
|
||||||
@ -1,224 +0,0 @@
|
|||||||
// Infinite Grid Shader
|
|
||||||
// Based on "The Best Darn Grid Shader (Yet)" by Ben Golus
|
|
||||||
|
|
||||||
#type vertex
|
|
||||||
#version 450 core
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
|
||||||
|
|
||||||
// camera
|
|
||||||
uniform mat4 u_View;
|
|
||||||
uniform mat4 u_Projection;
|
|
||||||
uniform vec3 u_CameraPosition;
|
|
||||||
|
|
||||||
out CameraData{
|
|
||||||
mat4 ViewProjection;
|
|
||||||
vec3 Position;
|
|
||||||
}CameraOutput;
|
|
||||||
|
|
||||||
out vec3 v_NearPoint;
|
|
||||||
out vec3 v_FarPoint;
|
|
||||||
|
|
||||||
vec3 unprojectPoint(float x, float y, float z) {
|
|
||||||
mat4 viewInv = inverse(u_View);
|
|
||||||
mat4 projInv = inverse(u_Projection);
|
|
||||||
vec4 unprojectedPoint = viewInv * projInv * vec4(x, y, z, 1.0);
|
|
||||||
return unprojectedPoint.xyz / unprojectedPoint.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
v_NearPoint = unprojectPoint(a_Position.x, a_Position.y, 0.0);
|
|
||||||
v_FarPoint = unprojectPoint(a_Position.x, a_Position.y, 1.0);
|
|
||||||
|
|
||||||
CameraOutput.ViewProjection = u_Projection * u_View;
|
|
||||||
CameraOutput.Position = u_CameraPosition;
|
|
||||||
|
|
||||||
gl_Position = vec4(a_Position, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#type fragment
|
|
||||||
#version 450 core
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Color;
|
|
||||||
|
|
||||||
in vec3 v_NearPoint;
|
|
||||||
in vec3 v_FarPoint;
|
|
||||||
|
|
||||||
in CameraData{
|
|
||||||
mat4 ViewProjection;
|
|
||||||
vec3 Position;
|
|
||||||
}CameraInput;
|
|
||||||
|
|
||||||
// Grid plane: 0 = XZ (Y up), 1 = XY (Z forward), 2 = YZ (X right)
|
|
||||||
uniform int u_GridPlane;
|
|
||||||
uniform float u_GridScale;
|
|
||||||
uniform vec4 u_GridColorThin;
|
|
||||||
uniform vec4 u_GridColorThick;
|
|
||||||
uniform vec4 u_AxisColorX;
|
|
||||||
uniform vec4 u_AxisColorZ;
|
|
||||||
uniform float u_FadeDistance;
|
|
||||||
|
|
||||||
float computeDepth(vec3 pos) {
|
|
||||||
vec4 clipSpacePos = CameraInput.ViewProjection * vec4(pos, 1.0);
|
|
||||||
return clipSpacePos.z / clipSpacePos.w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the plane normal based on grid plane type
|
|
||||||
vec3 getPlaneNormal() {
|
|
||||||
if (u_GridPlane == 1) return vec3(0.0, 0.0, 1.0); // XY plane, Z normal
|
|
||||||
if (u_GridPlane == 2) return vec3(1.0, 0.0, 0.0); // YZ plane, X normal
|
|
||||||
return vec3(0.0, 1.0, 0.0); // XZ plane, Y normal (default)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get 2D coordinates on the plane
|
|
||||||
vec2 getPlaneCoords(vec3 pos) {
|
|
||||||
if (u_GridPlane == 1) return pos.xy; // XY plane
|
|
||||||
if (u_GridPlane == 2) return pos.yz; // YZ plane
|
|
||||||
return pos.xz; // XZ plane (default)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the component perpendicular to the plane (for axis drawing)
|
|
||||||
vec2 getAxisCoords(vec3 pos) {
|
|
||||||
// Returns the two coordinates used for drawing axis lines
|
|
||||||
// First component -> first axis color, Second component -> second axis color
|
|
||||||
if (u_GridPlane == 1) return vec2(pos.x, pos.y); // XY: X-axis and Y-axis
|
|
||||||
if (u_GridPlane == 2) return vec2(pos.y, pos.z); // YZ: Y-axis and Z-axis
|
|
||||||
return vec2(pos.x, pos.z); // XZ: X-axis and Z-axis
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate t for ray-plane intersection
|
|
||||||
float rayPlaneIntersection(vec3 nearPoint, vec3 farPoint) {
|
|
||||||
vec3 rayDir = farPoint - nearPoint;
|
|
||||||
|
|
||||||
if (u_GridPlane == 1) {
|
|
||||||
// XY plane (z = 0)
|
|
||||||
if (abs(rayDir.z) < 0.0001) return -1.0;
|
|
||||||
return -nearPoint.z / rayDir.z;
|
|
||||||
}
|
|
||||||
if (u_GridPlane == 2) {
|
|
||||||
// YZ plane (x = 0)
|
|
||||||
if (abs(rayDir.x) < 0.0001) return -1.0;
|
|
||||||
return -nearPoint.x / rayDir.x;
|
|
||||||
}
|
|
||||||
// XZ plane (y = 0) - default
|
|
||||||
if (abs(rayDir.y) < 0.0001) return -1.0;
|
|
||||||
return -nearPoint.y / rayDir.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get view angle component for normal fade
|
|
||||||
float getViewAngleComponent(vec3 viewDir) {
|
|
||||||
if (u_GridPlane == 1) return abs(viewDir.z); // XY plane
|
|
||||||
if (u_GridPlane == 2) return abs(viewDir.x); // YZ plane
|
|
||||||
return abs(viewDir.y); // XZ plane
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pristine grid - single pixel line with proper AA
|
|
||||||
float pristineGridLine(vec2 uv) {
|
|
||||||
vec2 dudv = fwidth(uv);
|
|
||||||
vec2 uvMod = fract(uv);
|
|
||||||
vec2 uvDist = min(uvMod, 1.0 - uvMod);
|
|
||||||
vec2 distInPixels = uvDist / dudv;
|
|
||||||
vec2 lineAlpha = 1.0 - smoothstep(0.0, 1.0, distInPixels);
|
|
||||||
float alpha = max(lineAlpha.x, lineAlpha.y);
|
|
||||||
float density = max(dudv.x, dudv.y);
|
|
||||||
float densityFade = 1.0 - smoothstep(0.5, 1.0, density);
|
|
||||||
return alpha * densityFade;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Axis line - single pixel wide
|
|
||||||
float axisLineAA(float coord, float dudv) {
|
|
||||||
float distInPixels = abs(coord) / dudv;
|
|
||||||
return 1.0 - smoothstep(0.0, 1.5, distInPixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
|
|
||||||
|
|
||||||
float t = rayPlaneIntersection(v_NearPoint, v_FarPoint);
|
|
||||||
|
|
||||||
if (t < 0.0) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 fragPos3D = v_NearPoint + t * (v_FarPoint - v_NearPoint);
|
|
||||||
float depth = computeDepth(fragPos3D);
|
|
||||||
|
|
||||||
if (depth > 1.0 || depth < -1.0) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 worldPos = getPlaneCoords(fragPos3D);
|
|
||||||
|
|
||||||
// === Fading ===
|
|
||||||
|
|
||||||
// Radial fade
|
|
||||||
float dist = length(fragPos3D - CameraInput.Position);
|
|
||||||
float radialFade = 1.0 - smoothstep(u_FadeDistance * 0.3, u_FadeDistance, dist);
|
|
||||||
|
|
||||||
// Normal fade (view angle)
|
|
||||||
vec3 viewDir = normalize(fragPos3D - CameraInput.Position);
|
|
||||||
float viewAngle = getViewAngleComponent(viewDir);
|
|
||||||
float normalFade = smoothstep(0.0, 0.15, viewAngle);
|
|
||||||
|
|
||||||
float fadeFactor = radialFade * normalFade;
|
|
||||||
|
|
||||||
if (fadeFactor < 0.001) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Grid calculation ===
|
|
||||||
|
|
||||||
vec2 gridCoord1 = worldPos / u_GridScale;
|
|
||||||
vec2 gridCoord10 = worldPos / (u_GridScale * 10.0);
|
|
||||||
|
|
||||||
float grid1 = pristineGridLine(gridCoord1);
|
|
||||||
float grid10 = pristineGridLine(gridCoord10);
|
|
||||||
|
|
||||||
// LOD blend
|
|
||||||
vec2 deriv1 = fwidth(gridCoord1);
|
|
||||||
float lodFactor = smoothstep(20.0, 200.0, dist);
|
|
||||||
// float lodFactor = smoothstep(0.2, 0.5, max(deriv1.x, deriv1.y));
|
|
||||||
|
|
||||||
// Combine grids
|
|
||||||
float gridIntensity = mix(max(grid1, grid10 * 0.7), grid10, lodFactor);
|
|
||||||
|
|
||||||
// Grid color
|
|
||||||
vec3 gridColor = mix(u_GridColorThin.rgb, u_GridColorThick.rgb, lodFactor);
|
|
||||||
float baseAlpha = mix(u_GridColorThin.a, u_GridColorThick.a, lodFactor);
|
|
||||||
float gridAlpha = baseAlpha * gridIntensity * fadeFactor;
|
|
||||||
|
|
||||||
// === Axis lines ===
|
|
||||||
|
|
||||||
vec2 axisCoords = getAxisCoords(fragPos3D);
|
|
||||||
vec2 worldDeriv = fwidth(worldPos);
|
|
||||||
|
|
||||||
// First axis (uses AxisColorX - typically red)
|
|
||||||
float axis1Alpha = axisLineAA(axisCoords.y, worldDeriv.y) * fadeFactor;
|
|
||||||
// Second axis (uses AxisColorZ - typically blue)
|
|
||||||
float axis2Alpha = axisLineAA(axisCoords.x, worldDeriv.x) * fadeFactor;
|
|
||||||
|
|
||||||
// === Final composition ===
|
|
||||||
|
|
||||||
vec3 finalColor = gridColor;
|
|
||||||
float finalAlpha = gridAlpha;
|
|
||||||
|
|
||||||
// Blend axis colors
|
|
||||||
if (axis2Alpha > 0.001) {
|
|
||||||
float blend = axis2Alpha * u_AxisColorZ.a;
|
|
||||||
finalColor = mix(finalColor, u_AxisColorZ.rgb, blend);
|
|
||||||
finalAlpha = max(finalAlpha, blend);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (axis1Alpha > 0.001) {
|
|
||||||
float blend = axis1Alpha * u_AxisColorX.a;
|
|
||||||
finalColor = mix(finalColor, u_AxisColorX.rgb, blend);
|
|
||||||
finalAlpha = max(finalAlpha, blend);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finalAlpha < 0.001) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
gl_FragDepth = depth * 0.5 + 0.5;
|
|
||||||
o_Color = vec4(finalColor, finalAlpha);
|
|
||||||
}
|
|
||||||
@ -4,10 +4,13 @@
|
|||||||
#version 430
|
#version 430
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 1) in vec2 a_TexCoord;
|
||||||
|
|
||||||
uniform mat4 u_ViewProjection;
|
uniform mat4 u_ViewProjection;
|
||||||
uniform mat4 u_Transform;
|
uniform mat4 u_Transform;
|
||||||
|
|
||||||
|
out vec2 v_TexCoord;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
|
gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
// Outline Shader
|
|
||||||
|
|
||||||
#type vertex
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
|
||||||
|
|
||||||
layout(location = 5) in ivec4 a_BoneIndices;
|
|
||||||
layout(location = 6) in vec4 a_BoneWeights;
|
|
||||||
|
|
||||||
uniform mat4 u_ViewProjection;
|
|
||||||
uniform mat4 u_Transform;
|
|
||||||
|
|
||||||
const int MAX_BONES = 100;
|
|
||||||
uniform mat4 u_BoneTransforms[100];
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
mat4 boneTransform = u_BoneTransforms[a_BoneIndices[0]] * a_BoneWeights[0];
|
|
||||||
boneTransform += u_BoneTransforms[a_BoneIndices[1]] * a_BoneWeights[1];
|
|
||||||
boneTransform += u_BoneTransforms[a_BoneIndices[2]] * a_BoneWeights[2];
|
|
||||||
boneTransform += u_BoneTransforms[a_BoneIndices[3]] * a_BoneWeights[3];
|
|
||||||
|
|
||||||
vec4 localPosition = boneTransform * vec4(a_Position, 1.0);
|
|
||||||
gl_Position = u_ViewProjection * u_Transform * localPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
#type fragment
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
color = vec4(1.0, 0.5, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
// -----------------------------
|
// -----------------------------
|
||||||
// -- Based on Hazel PBR shader --
|
// -- From Hazel Engine PBR shader --
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||||
// Currently heavily updated.
|
// Currently heavily updated.
|
||||||
//
|
//
|
||||||
// References upon which this is based:
|
// References upon which this is based:
|
||||||
// - Unreal Engine 4 PBR notes (https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf)
|
// - Unreal Engine 4 PBR notes (https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf)
|
||||||
@ -21,25 +21,19 @@ layout(location = 4) in vec2 a_TexCoord;
|
|||||||
layout(location = 5) in ivec4 a_BoneIndices;
|
layout(location = 5) in ivec4 a_BoneIndices;
|
||||||
layout(location = 6) in vec4 a_BoneWeights;
|
layout(location = 6) in vec4 a_BoneWeights;
|
||||||
|
|
||||||
|
uniform mat4 u_ViewProjectionMatrix;
|
||||||
|
uniform mat4 u_Transform;
|
||||||
|
|
||||||
const int MAX_BONES = 100;
|
const int MAX_BONES = 100;
|
||||||
uniform mat4 u_BoneTransforms[100];
|
uniform mat4 u_BoneTransforms[100];
|
||||||
|
|
||||||
uniform mat4 u_ViewProjectionMatrix;
|
|
||||||
uniform mat4 u_ViewMatrix;
|
|
||||||
uniform mat4 u_Transform;
|
|
||||||
|
|
||||||
uniform mat4 u_LightSpaceMatrix;
|
|
||||||
|
|
||||||
out VertexOutput
|
out VertexOutput
|
||||||
{
|
{
|
||||||
vec3 WorldPosition;
|
vec3 WorldPosition;
|
||||||
vec3 Normal;
|
vec3 Normal;
|
||||||
vec2 TexCoord;
|
vec2 TexCoord;
|
||||||
mat3 WorldNormals;
|
mat3 WorldNormals;
|
||||||
mat3 WorldTransform;
|
vec3 Binormal;
|
||||||
vec3 Binormal;
|
|
||||||
vec3 ViewPosition;
|
|
||||||
vec4 FragPosLightSpace;
|
|
||||||
} vs_Output;
|
} vs_Output;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
@ -49,21 +43,15 @@ void main()
|
|||||||
boneTransform += u_BoneTransforms[a_BoneIndices[2]] * a_BoneWeights[2];
|
boneTransform += u_BoneTransforms[a_BoneIndices[2]] * a_BoneWeights[2];
|
||||||
boneTransform += u_BoneTransforms[a_BoneIndices[3]] * a_BoneWeights[3];
|
boneTransform += u_BoneTransforms[a_BoneIndices[3]] * a_BoneWeights[3];
|
||||||
|
|
||||||
vec4 localPosition = boneTransform * vec4(a_Position, 1.0);
|
vec4 localPosition = boneTransform * vec4(a_Position, 1.0);
|
||||||
|
|
||||||
vs_Output.WorldPosition = vec3(u_Transform * boneTransform * vec4(a_Position, 1.0));
|
vs_Output.WorldPosition = vec3(u_Transform * boneTransform * vec4(a_Position, 1.0));
|
||||||
vs_Output.Normal = mat3(u_Transform) * mat3(boneTransform) * a_Normal;
|
vs_Output.Normal = mat3(u_Transform) * mat3(boneTransform) * a_Normal;
|
||||||
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
|
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
|
||||||
vs_Output.WorldNormals = mat3(u_Transform) * mat3(a_Tangent, a_Binormal, a_Normal);
|
vs_Output.WorldNormals = mat3(u_Transform) * mat3(a_Tangent, a_Binormal, a_Normal);
|
||||||
vs_Output.WorldTransform = mat3(u_Transform);
|
vs_Output.Binormal = mat3(boneTransform) * a_Binormal;
|
||||||
vs_Output.Binormal = a_Binormal;
|
|
||||||
|
|
||||||
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * localPosition;
|
gl_Position = u_ViewProjectionMatrix * u_Transform * localPosition;
|
||||||
|
|
||||||
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
|
||||||
|
|
||||||
// gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
|
||||||
gl_Position = u_ViewProjectionMatrix * u_Transform * localPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#type fragment
|
#type fragment
|
||||||
@ -73,121 +61,102 @@ const float PI = 3.141592;
|
|||||||
const float Epsilon = 0.00001;
|
const float Epsilon = 0.00001;
|
||||||
|
|
||||||
const int LightCount = 1;
|
const int LightCount = 1;
|
||||||
|
|
||||||
|
// Constant normal incidence Fresnel factor for all dielectrics.
|
||||||
const vec3 Fdielectric = vec3(0.04);
|
const vec3 Fdielectric = vec3(0.04);
|
||||||
|
|
||||||
struct DirectionalLight {
|
struct Light {
|
||||||
vec3 Direction;
|
vec3 Direction;
|
||||||
vec3 Radiance;
|
vec3 Radiance;
|
||||||
float Intensity;
|
float Multiplier;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
in VertexOutput
|
in VertexOutput
|
||||||
{
|
{
|
||||||
vec3 WorldPosition;
|
vec3 WorldPosition;
|
||||||
vec3 Normal;
|
vec3 Normal;
|
||||||
vec2 TexCoord;
|
vec2 TexCoord;
|
||||||
mat3 WorldNormals;
|
mat3 WorldNormals;
|
||||||
mat3 WorldTransform;
|
vec3 Binormal;
|
||||||
vec3 Binormal;
|
|
||||||
vec3 ViewPosition;
|
|
||||||
vec4 FragPosLightSpace;
|
|
||||||
} vs_Input;
|
} vs_Input;
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
layout(location=0) out vec4 color;
|
||||||
layout(location = 1) out vec4 o_BloomColor;
|
|
||||||
|
|
||||||
uniform DirectionalLight u_DirectionalLights;
|
uniform Light lights;
|
||||||
uniform vec3 u_CameraPosition;
|
uniform vec3 u_CameraPosition;
|
||||||
|
|
||||||
uniform int u_PointLightCount;
|
// PBR texture inputs
|
||||||
uniform PointLight u_PointLights;
|
|
||||||
|
|
||||||
uniform int u_SpotLightCount;
|
|
||||||
uniform SpotLight u_SpotLights;
|
|
||||||
|
|
||||||
|
|
||||||
// PBR
|
|
||||||
uniform sampler2D u_AlbedoTexture;
|
uniform sampler2D u_AlbedoTexture;
|
||||||
uniform sampler2D u_NormalTexture;
|
uniform sampler2D u_NormalTexture;
|
||||||
uniform sampler2D u_MetalnessTexture;
|
uniform sampler2D u_MetalnessTexture;
|
||||||
uniform sampler2D u_RoughnessTexture;
|
uniform sampler2D u_RoughnessTexture;
|
||||||
|
|
||||||
// environment
|
// Environment maps
|
||||||
uniform samplerCube u_EnvRadianceTex;
|
uniform samplerCube u_EnvRadianceTex;
|
||||||
uniform samplerCube u_EnvIrradianceTex;
|
uniform samplerCube u_EnvIrradianceTex;
|
||||||
|
|
||||||
// BRDF LUT
|
// BRDF LUT
|
||||||
uniform sampler2D u_BRDFLUTTexture;
|
uniform sampler2D u_BRDFLUTTexture;
|
||||||
|
|
||||||
uniform float u_IBLContribution;
|
uniform vec3 u_AlbedoColor;
|
||||||
uniform float u_BloomThreshold;
|
|
||||||
uniform float u_EnvMapRotation;
|
|
||||||
|
|
||||||
// baseColor
|
|
||||||
uniform vec3 u_AlbedoColor;
|
|
||||||
uniform float u_Metalness;
|
uniform float u_Metalness;
|
||||||
uniform float u_Roughness;
|
uniform float u_Roughness;
|
||||||
|
|
||||||
// textureToggle
|
uniform float u_EnvMapRotation;
|
||||||
|
|
||||||
|
// Toggles
|
||||||
|
uniform float u_RadiancePrefilter;
|
||||||
uniform float u_AlbedoTexToggle;
|
uniform float u_AlbedoTexToggle;
|
||||||
uniform float u_NormalTexToggle;
|
uniform float u_NormalTexToggle;
|
||||||
uniform float u_MetalnessTexToggle;
|
uniform float u_MetalnessTexToggle;
|
||||||
uniform float u_RoughnessTexToggle;
|
uniform float u_RoughnessTexToggle;
|
||||||
|
|
||||||
// shadow
|
|
||||||
uniform sampler2D u_ShadowMap;
|
|
||||||
uniform float u_ShadowBias;
|
|
||||||
uniform float u_ShadowSoftness;
|
|
||||||
uniform float u_ShadowIntensity;
|
|
||||||
uniform int u_ShadowEnabled;
|
|
||||||
|
|
||||||
struct PBRParameters
|
struct PBRParameters
|
||||||
{
|
{
|
||||||
vec3 Albedo;
|
vec3 Albedo;
|
||||||
float Roughness;
|
float Roughness;
|
||||||
float Metalness;
|
float Metalness;
|
||||||
vec3 Normal;
|
|
||||||
vec3 View;
|
vec3 Normal;
|
||||||
float NdotV;
|
vec3 View;
|
||||||
|
float NdotV;
|
||||||
};
|
};
|
||||||
|
|
||||||
PBRParameters m_Params;
|
PBRParameters m_Params;
|
||||||
|
|
||||||
// ---------- PBR param func ----------
|
// GGX/Towbridge-Reitz normal distribution function.
|
||||||
|
// Uses Disney's reparametrization of alpha = roughness^2
|
||||||
float ndfGGX(float cosLh, float roughness)
|
float ndfGGX(float cosLh, float roughness)
|
||||||
{
|
{
|
||||||
float alpha = roughness * roughness;
|
float alpha = roughness * roughness;
|
||||||
float alphaSq = alpha * alpha;
|
float alphaSq = alpha * alpha;
|
||||||
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
|
||||||
return alphaSq / (PI * denom * denom);
|
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||||
|
return alphaSq / (PI * denom * denom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single term for separable Schlick-GGX below.
|
||||||
|
float gaSchlickG1(float cosTheta, float k)
|
||||||
|
{
|
||||||
|
return cosTheta / (cosTheta * (1.0 - k) + k);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||||
|
float gaSchlickGGX(float cosLi, float NdotV, float roughness)
|
||||||
|
{
|
||||||
|
float r = roughness + 1.0;
|
||||||
|
float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||||
|
return gaSchlickG1(cosLi, k) * gaSchlickG1(NdotV, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||||
{
|
{
|
||||||
float r = (roughness + 1.0);
|
float r = (roughness + 1.0);
|
||||||
float k = (r * r) / 8.0;
|
float k = (r*r) / 8.0;
|
||||||
float nom = NdotV;
|
|
||||||
|
float nom = NdotV;
|
||||||
float denom = NdotV * (1.0 - k) + k;
|
float denom = NdotV * (1.0 - k) + k;
|
||||||
|
|
||||||
return nom / denom;
|
return nom / denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,275 +166,165 @@ float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
|||||||
float NdotL = max(dot(N, L), 0.0);
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||||
|
|
||||||
return ggx1 * ggx2;
|
return ggx1 * ggx2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shlick's approximation of the Fresnel factor.
|
||||||
vec3 fresnelSchlick(vec3 F0, float cosTheta)
|
vec3 fresnelSchlick(vec3 F0, float cosTheta)
|
||||||
{
|
{
|
||||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness)
|
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness)
|
||||||
{
|
{
|
||||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- direction light ----------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, PBRParameters params)
|
// The following code (from Unreal Engine 4's paper) shows how to filter the environment map
|
||||||
|
// for different roughnesses. This is mean to be computed offline and stored in cube map mips,
|
||||||
|
// so turning this on online will cause poor performance
|
||||||
|
float RadicalInverse_VdC(uint bits)
|
||||||
{
|
{
|
||||||
vec3 L = normalize(-light.Direction);
|
bits = (bits << 16u) | (bits >> 16u);
|
||||||
vec3 Lradiance = light.Radiance * light.Intensity;
|
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||||
|
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||||
vec3 Lh = normalize(L + params.View);
|
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||||
float cosLi = max(0.0, dot(params.Normal, L));
|
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||||
float cosLh = max(0.0, dot(params.Normal, Lh));
|
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||||
|
|
||||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View)));
|
|
||||||
float D = ndfGGX(cosLh, params.Roughness);
|
|
||||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
|
||||||
|
|
||||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
|
||||||
vec3 diffuseBRDF = kd * params.Albedo;
|
|
||||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
|
||||||
|
|
||||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 ComputePointLight(PointLight light, vec3 F0, PBRParameters params, vec3 worldPos)
|
vec2 Hammersley(uint i, uint N)
|
||||||
{
|
{
|
||||||
vec3 lightVec = light.Position - worldPos;
|
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||||
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 + params.View);
|
|
||||||
float cosLi = max(0.0, dot(params.Normal, L));
|
|
||||||
float cosLh = max(0.0, dot(params.Normal, Lh));
|
|
||||||
|
|
||||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View)));
|
|
||||||
float D = ndfGGX(cosLh, params.Roughness);
|
|
||||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
|
||||||
|
|
||||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
|
||||||
vec3 diffuseBRDF = kd * params.Albedo;
|
|
||||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
|
||||||
|
|
||||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 ComputeSpotLight(SpotLight light, vec3 F0, PBRParameters params, vec3 worldPos)
|
vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
|
||||||
{
|
{
|
||||||
vec3 lightVec = light.Position - worldPos;
|
float a = Roughness * Roughness;
|
||||||
float dist = length(lightVec);
|
float Phi = 2 * PI * Xi.x;
|
||||||
if (dist > light.Range) return vec3(0.0);
|
float CosTheta = sqrt( (1 - Xi.y) / ( 1 + (a*a - 1) * Xi.y ) );
|
||||||
|
float SinTheta = sqrt( 1 - CosTheta * CosTheta );
|
||||||
vec3 L = lightVec / dist;
|
vec3 H;
|
||||||
vec3 Lradiance = light.Radiance * light.Intensity;
|
H.x = SinTheta * cos( Phi );
|
||||||
|
H.y = SinTheta * sin( Phi );
|
||||||
// 距离衰减
|
H.z = CosTheta;
|
||||||
float attenuation = 1.0 / (dist * dist + 0.0001);
|
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0,0,1) : vec3(1,0,0);
|
||||||
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
|
vec3 TangentX = normalize( cross( UpVector, N ) );
|
||||||
rangeFactor = rangeFactor * rangeFactor;
|
vec3 TangentY = cross( N, TangentX );
|
||||||
attenuation *= rangeFactor;
|
// Tangent to world space
|
||||||
|
return TangentX * H.x + TangentY * H.y + N * H.z;
|
||||||
// 角度衰减(聚光锥)
|
|
||||||
float cosAngle = dot(-L, normalize(light.Direction)); // 光方向指向外,所以用 -L
|
|
||||||
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 + params.View);
|
|
||||||
float cosLi = max(0.0, dot(params.Normal, L));
|
|
||||||
float cosLh = max(0.0, dot(params.Normal, Lh));
|
|
||||||
|
|
||||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View)));
|
|
||||||
float D = ndfGGX(cosLh, params.Roughness);
|
|
||||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
|
||||||
|
|
||||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
|
||||||
vec3 diffuseBRDF = kd * params.Albedo;
|
|
||||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
|
||||||
|
|
||||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float TotalWeight = 0.0;
|
||||||
|
|
||||||
|
vec3 PrefilterEnvMap(float Roughness, vec3 R)
|
||||||
vec3 Lighting(vec3 F0)
|
|
||||||
{
|
{
|
||||||
vec3 result = vec3(0.0);
|
vec3 N = R;
|
||||||
for(int i = 0; i < LightCount; i++)
|
vec3 V = R;
|
||||||
{
|
vec3 PrefilteredColor = vec3(0.0);
|
||||||
vec3 Li = u_DirectionalLights.Direction;
|
int NumSamples = 1024;
|
||||||
vec3 Lradiance = u_DirectionalLights.Radiance * u_DirectionalLights.Intensity;
|
for(int i = 0; i < NumSamples; i++)
|
||||||
vec3 Lh = normalize(Li + m_Params.View);
|
{
|
||||||
|
vec2 Xi = Hammersley(i, NumSamples);
|
||||||
float cosLi = max(0.0, dot(m_Params.Normal, Li));
|
vec3 H = ImportanceSampleGGX(Xi, Roughness, N);
|
||||||
float cosLh = max(0.0, dot(m_Params.Normal, Lh));
|
vec3 L = 2 * dot(V, H) * H - V;
|
||||||
|
float NoL = clamp(dot(N, L), 0.0, 1.0);
|
||||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, m_Params.View)));
|
if (NoL > 0)
|
||||||
float D = ndfGGX(cosLh, m_Params.Roughness);
|
{
|
||||||
float G = GeometrySmith(m_Params.Normal, m_Params.View, Li, m_Params.Roughness);
|
PrefilteredColor += texture(u_EnvRadianceTex, L).rgb * NoL;
|
||||||
|
TotalWeight += NoL;
|
||||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
}
|
||||||
vec3 diffuseBRDF = kd * m_Params.Albedo;
|
}
|
||||||
|
return PrefilteredColor / TotalWeight;
|
||||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * m_Params.NdotV);
|
|
||||||
|
|
||||||
result += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- IBL ----------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
vec3 RotateVectorAboutY(float angle, vec3 vec)
|
vec3 RotateVectorAboutY(float angle, vec3 vec)
|
||||||
{
|
{
|
||||||
angle = radians(angle);
|
angle = radians(angle);
|
||||||
mat3 rotationMatrix = mat3(
|
mat3x3 rotationMatrix ={vec3(cos(angle),0.0,sin(angle)),
|
||||||
vec3(cos(angle), 0.0, sin(angle)),
|
vec3(0.0,1.0,0.0),
|
||||||
vec3(0.0, 1.0, 0.0),
|
vec3(-sin(angle),0.0,cos(angle))};
|
||||||
vec3(-sin(angle), 0.0, cos(angle))
|
|
||||||
);
|
|
||||||
return rotationMatrix * vec;
|
return rotationMatrix * vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 Lighting(vec3 F0)
|
||||||
|
{
|
||||||
|
vec3 result = vec3(0.0);
|
||||||
|
for(int i = 0; i < LightCount; i++)
|
||||||
|
{
|
||||||
|
vec3 Li = -lights.Direction;
|
||||||
|
vec3 Lradiance = lights.Radiance * lights.Multiplier;
|
||||||
|
vec3 Lh = normalize(Li + m_Params.View);
|
||||||
|
|
||||||
|
// Calculate angles between surface normal and various light vectors.
|
||||||
|
float cosLi = max(0.0, dot(m_Params.Normal, Li));
|
||||||
|
float cosLh = max(0.0, dot(m_Params.Normal, Lh));
|
||||||
|
|
||||||
|
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, m_Params.View)));
|
||||||
|
float D = ndfGGX(cosLh, m_Params.Roughness);
|
||||||
|
float G = gaSchlickGGX(cosLi, m_Params.NdotV, m_Params.Roughness);
|
||||||
|
|
||||||
|
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||||
|
vec3 diffuseBRDF = kd * m_Params.Albedo;
|
||||||
|
|
||||||
|
// Cook-Torrance
|
||||||
|
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * m_Params.NdotV);
|
||||||
|
|
||||||
|
result += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
vec3 IBL(vec3 F0, vec3 Lr)
|
vec3 IBL(vec3 F0, vec3 Lr)
|
||||||
{
|
{
|
||||||
vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
|
vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
|
||||||
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
|
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
|
||||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||||
vec3 diffuseIBL = m_Params.Albedo * irradiance;
|
vec3 diffuseIBL = m_Params.Albedo * irradiance;
|
||||||
|
|
||||||
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
||||||
vec3 specularIrradiance = textureLod(
|
float NoV = clamp(m_Params.NdotV, 0.0, 1.0);
|
||||||
u_EnvRadianceTex,
|
vec3 R = 2.0 * dot(m_Params.View, m_Params.Normal) * m_Params.Normal - m_Params.View;
|
||||||
RotateVectorAboutY(u_EnvMapRotation, Lr),
|
vec3 specularIrradiance = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), (m_Params.Roughness) * u_EnvRadianceTexLevels).rgb;
|
||||||
m_Params.Roughness * u_EnvRadianceTexLevels
|
|
||||||
).rgb;
|
|
||||||
|
|
||||||
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg;
|
// Sample BRDF Lut, 1.0 - roughness for y-coord because texture was generated (in Sparky) for gloss model
|
||||||
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg;
|
||||||
|
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
||||||
|
|
||||||
return kd * diffuseIBL + specularIBL;
|
return kd * diffuseIBL + specularIBL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// shadow
|
|
||||||
|
|
||||||
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
|
||||||
{
|
|
||||||
// Perspective divide
|
|
||||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
|
||||||
|
|
||||||
// Transform to [0,1] range
|
|
||||||
projCoords = projCoords * 0.5 + 0.5;
|
|
||||||
|
|
||||||
// If outside shadow map bounds, assume no shadow
|
|
||||||
if(projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
// Get closest depth value from light's perspective
|
|
||||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
|
||||||
float currentDepth = projCoords.z;
|
|
||||||
|
|
||||||
// Calculate bias based on surface angle
|
|
||||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
|
||||||
|
|
||||||
// PCF (Percentage Closer Filtering) for soft shadows
|
|
||||||
float shadow = 0.0;
|
|
||||||
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
|
||||||
int pcfRange = int(u_ShadowSoftness);
|
|
||||||
int sampleCount = 0;
|
|
||||||
|
|
||||||
for(int x = -pcfRange; x <= pcfRange; ++x)
|
|
||||||
{
|
|
||||||
for(int y = -pcfRange; y <= pcfRange; ++y)
|
|
||||||
{
|
|
||||||
float pcfDepth = texture(u_ShadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
|
|
||||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
|
||||||
sampleCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shadow /= float(sampleCount);
|
|
||||||
|
|
||||||
return shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
|
||||||
{
|
|
||||||
if (u_ShadowEnabled == 0) return 1.0;
|
|
||||||
|
|
||||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
|
||||||
projCoords = projCoords * 0.5 + 0.5;
|
|
||||||
|
|
||||||
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
|
||||||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
|
||||||
projCoords.z > 1.0) return 1.0;
|
|
||||||
|
|
||||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
|
||||||
float currentDepth = projCoords.z;
|
|
||||||
|
|
||||||
float bias = max(u_ShadowBias * (1.0 - NdotL), u_ShadowBias * 0.5);
|
|
||||||
|
|
||||||
float shadow = (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
|
|
||||||
return mix(1.0, 1.0 - u_ShadowIntensity, shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
|
// Standard PBR inputs
|
||||||
m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
|
||||||
m_Params.Roughness = u_RoughnessTexToggle > 0.5 ? texture(u_RoughnessTexture, vs_Input.TexCoord).r : u_Roughness;
|
m_Params.Metalness = u_MetalnessTexToggle > 0.5 ? texture(u_MetalnessTexture, vs_Input.TexCoord).r : u_Metalness;
|
||||||
m_Params.Roughness = max(m_Params.Roughness, 0.05);
|
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); // Minimum roughness of 0.05 to keep specular highlight
|
||||||
|
|
||||||
// normal
|
// Normals (either from vertex or map)
|
||||||
m_Params.Normal = normalize(vs_Input.Normal);
|
m_Params.Normal = normalize(vs_Input.Normal);
|
||||||
if (u_NormalTexToggle > 0.5)
|
if (u_NormalTexToggle > 0.5)
|
||||||
{
|
{
|
||||||
m_Params.Normal = normalize(2.0 * texture(u_NormalTexture, vs_Input.TexCoord).rgb - 1.0);
|
m_Params.Normal = normalize(2.0 * texture(u_NormalTexture, vs_Input.TexCoord).rgb - 1.0);
|
||||||
m_Params.Normal = normalize(vs_Input.WorldNormals * m_Params.Normal);
|
m_Params.Normal = normalize(vs_Input.WorldNormals * m_Params.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);
|
||||||
|
|
||||||
|
// Specular reflection vector
|
||||||
|
vec3 Lr = 2.0 * m_Params.NdotV * m_Params.Normal - m_Params.View;
|
||||||
|
|
||||||
vec3 Lr = 2.0 * m_Params.NdotV * m_Params.Normal - m_Params.View;
|
// Fresnel reflectance, metals use albedo
|
||||||
|
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
||||||
|
|
||||||
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
vec3 lightContribution = Lighting(F0);
|
||||||
|
vec3 iblContribution = IBL(F0, Lr);
|
||||||
|
|
||||||
float shadowFactor = 1.0;
|
color = vec4(lightContribution + iblContribution, 1.0);
|
||||||
if (u_ShadowEnabled > 0.5) {
|
|
||||||
float shadow = calculateShadow(vs_Input.FragPosLightSpace, m_Params.Normal, u_DirectionalLights.Direction);
|
|
||||||
shadowFactor = 1.0 - shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vec3 lightContribution = u_DirectionalLights.Intensity > 0.0 ? Lighting(F0) * shadowFactor : vec3(0.0);
|
|
||||||
|
|
||||||
if(u_PointLightCount > 0)
|
|
||||||
lightContribution += ComputePointLight(u_PointLights, F0, m_Params, vs_Input.WorldPosition);
|
|
||||||
|
|
||||||
if(u_SpotLightCount > 0)
|
|
||||||
lightContribution += ComputeSpotLight(u_SpotLights, F0, m_Params, vs_Input.WorldPosition);
|
|
||||||
|
|
||||||
|
|
||||||
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
|
|
||||||
|
|
||||||
color = vec4(lightContribution + iblContribution, 1.0);
|
|
||||||
|
|
||||||
// Bloom
|
|
||||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
|
||||||
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// -----------------------------
|
// -----------------------------
|
||||||
// -- Based on Hazel PBR shader --
|
// -- From Hazel Engine PBR shader --
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
// Note: this shader is still very much in progress. There are likely many bugs and future additions that will go in.
|
||||||
// Currently heavily updated.
|
// Currently heavily updated.
|
||||||
//
|
//
|
||||||
// References upon which this is based:
|
// References upon which this is based:
|
||||||
// - Unreal Engine 4 PBR notes (https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf)
|
// - Unreal Engine 4 PBR notes (https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf)
|
||||||
@ -19,36 +19,27 @@ layout(location = 3) in vec3 a_Binormal;
|
|||||||
layout(location = 4) in vec2 a_TexCoord;
|
layout(location = 4) in vec2 a_TexCoord;
|
||||||
|
|
||||||
uniform mat4 u_ViewProjectionMatrix;
|
uniform mat4 u_ViewProjectionMatrix;
|
||||||
uniform mat4 u_ViewMatrix;
|
|
||||||
uniform mat4 u_Transform;
|
uniform mat4 u_Transform;
|
||||||
|
|
||||||
uniform mat4 u_LightSpaceMatrix;
|
|
||||||
|
|
||||||
out VertexOutput
|
out VertexOutput
|
||||||
{
|
{
|
||||||
vec3 WorldPosition;
|
vec3 WorldPosition;
|
||||||
vec3 Normal;
|
vec3 Normal;
|
||||||
vec2 TexCoord;
|
vec2 TexCoord;
|
||||||
mat3 WorldNormals;
|
mat3 WorldNormals;
|
||||||
mat3 WorldTransform;
|
mat3 WorldTransform;
|
||||||
vec3 Binormal;
|
vec3 Binormal;
|
||||||
vec3 ViewPosition;
|
|
||||||
vec4 FragPosLightSpace;
|
|
||||||
} vs_Output;
|
} vs_Output;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vs_Output.WorldPosition = vec3(u_Transform * vec4(a_Position, 1.0));
|
vs_Output.WorldPosition = vec3(u_Transform * vec4(a_Position, 1.0));
|
||||||
vs_Output.Normal = mat3(u_Transform) * a_Normal;
|
vs_Output.Normal = mat3(u_Transform) * a_Normal;
|
||||||
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
|
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
|
||||||
vs_Output.WorldNormals = mat3(u_Transform) * mat3(a_Tangent, a_Binormal, a_Normal);
|
vs_Output.WorldNormals = mat3(u_Transform) * mat3(a_Tangent, a_Binormal, a_Normal);
|
||||||
vs_Output.WorldTransform = mat3(u_Transform);
|
vs_Output.WorldTransform = mat3(u_Transform);
|
||||||
vs_Output.Binormal = a_Binormal;
|
vs_Output.Binormal = a_Binormal;
|
||||||
|
|
||||||
vs_Output.FragPosLightSpace = u_LightSpaceMatrix * u_Transform * vec4(a_Position, 1.0);
|
|
||||||
|
|
||||||
vs_Output.ViewPosition = vec3(u_ViewMatrix * vec4(vs_Output.WorldPosition, 1.0));
|
|
||||||
|
|
||||||
gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
gl_Position = u_ViewProjectionMatrix * u_Transform * vec4(a_Position, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,101 +50,63 @@ const float PI = 3.141592;
|
|||||||
const float Epsilon = 0.00001;
|
const float Epsilon = 0.00001;
|
||||||
|
|
||||||
const int LightCount = 1;
|
const int LightCount = 1;
|
||||||
|
|
||||||
|
// Constant normal incidence Fresnel factor for all dielectrics.
|
||||||
const vec3 Fdielectric = vec3(0.04);
|
const vec3 Fdielectric = vec3(0.04);
|
||||||
|
|
||||||
struct DirectionalLight {
|
struct Light {
|
||||||
vec3 Direction;
|
vec3 Direction;
|
||||||
vec3 Radiance;
|
vec3 Radiance;
|
||||||
float Intensity;
|
float Multiplier;
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
in VertexOutput
|
in VertexOutput
|
||||||
{
|
{
|
||||||
vec3 WorldPosition;
|
vec3 WorldPosition;
|
||||||
vec3 Normal;
|
vec3 Normal;
|
||||||
vec2 TexCoord;
|
vec2 TexCoord;
|
||||||
mat3 WorldNormals;
|
mat3 WorldNormals;
|
||||||
mat3 WorldTransform;
|
mat3 WorldTransform;
|
||||||
vec3 Binormal;
|
vec3 Binormal;
|
||||||
vec3 ViewPosition;
|
|
||||||
vec4 FragPosLightSpace;
|
|
||||||
} vs_Input;
|
} vs_Input;
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
layout(location = 0) out vec4 color;
|
||||||
layout(location = 1) out vec4 o_BloomColor;
|
|
||||||
|
|
||||||
uniform DirectionalLight u_DirectionalLights;
|
|
||||||
|
|
||||||
uniform int u_PointLightCount;
|
|
||||||
uniform PointLight u_PointLights;
|
|
||||||
|
|
||||||
uniform int u_SpotLightCount;
|
|
||||||
uniform SpotLight u_SpotLights;
|
|
||||||
|
|
||||||
|
|
||||||
|
uniform Light lights;
|
||||||
uniform vec3 u_CameraPosition;
|
uniform vec3 u_CameraPosition;
|
||||||
|
|
||||||
// PBR
|
// PBR texture inputs
|
||||||
uniform sampler2D u_AlbedoTexture;
|
uniform sampler2D u_AlbedoTexture;
|
||||||
uniform sampler2D u_NormalTexture;
|
uniform sampler2D u_NormalTexture;
|
||||||
uniform sampler2D u_MetalnessTexture;
|
uniform sampler2D u_MetalnessTexture;
|
||||||
uniform sampler2D u_RoughnessTexture;
|
uniform sampler2D u_RoughnessTexture;
|
||||||
|
|
||||||
// environment
|
// Environment maps
|
||||||
uniform samplerCube u_EnvRadianceTex;
|
uniform samplerCube u_EnvRadianceTex;
|
||||||
uniform samplerCube u_EnvIrradianceTex;
|
uniform samplerCube u_EnvIrradianceTex;
|
||||||
|
|
||||||
// BRDF LUT
|
// BRDF LUT
|
||||||
uniform sampler2D u_BRDFLUTTexture;
|
uniform sampler2D u_BRDFLUTTexture;
|
||||||
|
|
||||||
uniform float u_IBLContribution;
|
uniform vec3 u_AlbedoColor;
|
||||||
uniform float u_BloomThreshold;
|
|
||||||
uniform float u_EnvMapRotation;
|
|
||||||
|
|
||||||
// baseColor
|
|
||||||
uniform vec3 u_AlbedoColor;
|
|
||||||
uniform float u_Metalness;
|
uniform float u_Metalness;
|
||||||
uniform float u_Roughness;
|
uniform float u_Roughness;
|
||||||
|
|
||||||
// textureToggle
|
uniform float u_EnvMapRotation;
|
||||||
|
|
||||||
|
// Toggles
|
||||||
|
uniform float u_RadiancePrefilter;
|
||||||
uniform float u_AlbedoTexToggle;
|
uniform float u_AlbedoTexToggle;
|
||||||
uniform float u_NormalTexToggle;
|
uniform float u_NormalTexToggle;
|
||||||
uniform float u_MetalnessTexToggle;
|
uniform float u_MetalnessTexToggle;
|
||||||
uniform float u_RoughnessTexToggle;
|
uniform float u_RoughnessTexToggle;
|
||||||
|
|
||||||
// shadow
|
|
||||||
uniform sampler2D u_ShadowMap;
|
|
||||||
uniform float u_ShadowBias;
|
|
||||||
uniform float u_ShadowSoftness;
|
|
||||||
uniform float u_ShadowIntensity;
|
|
||||||
uniform int u_ShadowEnabled;
|
|
||||||
|
|
||||||
struct PBRParameters
|
struct PBRParameters
|
||||||
{
|
{
|
||||||
vec3 Albedo;
|
vec3 Albedo;
|
||||||
float Roughness;
|
float Roughness;
|
||||||
float Metalness;
|
float Metalness;
|
||||||
|
|
||||||
vec3 Normal;
|
vec3 Normal;
|
||||||
vec3 View;
|
vec3 View;
|
||||||
float NdotV;
|
float NdotV;
|
||||||
@ -161,33 +114,53 @@ struct PBRParameters
|
|||||||
|
|
||||||
PBRParameters m_Params;
|
PBRParameters m_Params;
|
||||||
|
|
||||||
// ---------- PBR param func ----------
|
// GGX/Towbridge-Reitz normal distribution function.
|
||||||
|
// Uses Disney's reparametrization of alpha = roughness^2
|
||||||
float ndfGGX(float cosLh, float roughness)
|
float ndfGGX(float cosLh, float roughness)
|
||||||
{
|
{
|
||||||
float alpha = roughness * roughness;
|
float alpha = roughness * roughness;
|
||||||
float alphaSq = alpha * alpha;
|
float alphaSq = alpha * alpha;
|
||||||
|
|
||||||
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||||
return alphaSq / (PI * denom * denom);
|
return alphaSq / (PI * denom * denom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Single term for separable Schlick-GGX below.
|
||||||
|
float gaSchlickG1(float cosTheta, float k)
|
||||||
|
{
|
||||||
|
return cosTheta / (cosTheta * (1.0 - k) + k);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schlick-GGX approximation of geometric attenuation function using Smith's method.
|
||||||
|
float gaSchlickGGX(float cosLi, float NdotV, float roughness)
|
||||||
|
{
|
||||||
|
float r = roughness + 1.0;
|
||||||
|
float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights.
|
||||||
|
return gaSchlickG1(cosLi, k) * gaSchlickG1(NdotV, k);
|
||||||
|
}
|
||||||
|
|
||||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||||
{
|
{
|
||||||
float r = (roughness + 1.0);
|
float r = (roughness + 1.0);
|
||||||
float k = (r * r) / 8.0;
|
float k = (r*r) / 8.0;
|
||||||
float nom = NdotV;
|
|
||||||
float denom = NdotV * (1.0 - k) + k;
|
float nom = NdotV;
|
||||||
return nom / denom;
|
float denom = NdotV * (1.0 - k) + k;
|
||||||
|
|
||||||
|
return nom / denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||||
{
|
{
|
||||||
float NdotV = max(dot(N, V), 0.0);
|
float NdotV = max(dot(N, V), 0.0);
|
||||||
float NdotL = max(dot(N, L), 0.0);
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||||
return ggx1 * ggx2;
|
|
||||||
|
return ggx1 * ggx2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shlick's approximation of the Fresnel factor.
|
||||||
vec3 fresnelSchlick(vec3 F0, float cosTheta)
|
vec3 fresnelSchlick(vec3 F0, float cosTheta)
|
||||||
{
|
{
|
||||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
@ -195,97 +168,77 @@ vec3 fresnelSchlick(vec3 F0, float cosTheta)
|
|||||||
|
|
||||||
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness)
|
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness)
|
||||||
{
|
{
|
||||||
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
// The following code (from Unreal Engine 4's paper) shows how to filter the environment map
|
||||||
|
// for different roughnesses. This is mean to be computed offline and stored in cube map mips,
|
||||||
|
// so turning this on online will cause poor performance
|
||||||
|
float RadicalInverse_VdC(uint bits)
|
||||||
|
{
|
||||||
|
bits = (bits << 16u) | (bits >> 16u);
|
||||||
|
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||||
|
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||||
|
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||||
|
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||||
|
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- direction light ----------
|
vec2 Hammersley(uint i, uint N)
|
||||||
vec3 ComputeDirectionalLight(DirectionalLight light, vec3 F0, PBRParameters params)
|
|
||||||
{
|
{
|
||||||
vec3 L = normalize(-light.Direction);
|
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||||
vec3 Lradiance = light.Radiance * light.Intensity;
|
|
||||||
|
|
||||||
vec3 Lh = normalize(L + params.View);
|
|
||||||
float cosLi = max(0.0, dot(params.Normal, L));
|
|
||||||
float cosLh = max(0.0, dot(params.Normal, Lh));
|
|
||||||
|
|
||||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View)));
|
|
||||||
float D = ndfGGX(cosLh, params.Roughness);
|
|
||||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
|
||||||
|
|
||||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
|
||||||
vec3 diffuseBRDF = kd * params.Albedo;
|
|
||||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
|
||||||
|
|
||||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 ComputePointLight(PointLight light, vec3 F0, PBRParameters params, vec3 worldPos)
|
vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
|
||||||
{
|
{
|
||||||
vec3 lightVec = light.Position - worldPos;
|
float a = Roughness * Roughness;
|
||||||
float dist = length(lightVec);
|
float Phi = 2 * PI * Xi.x;
|
||||||
if (dist > light.Range) return vec3(0.0);
|
float CosTheta = sqrt( (1 - Xi.y) / ( 1 + (a*a - 1) * Xi.y ) );
|
||||||
|
float SinTheta = sqrt( 1 - CosTheta * CosTheta );
|
||||||
vec3 L = lightVec / dist;
|
vec3 H;
|
||||||
vec3 Lradiance = light.Radiance * light.Intensity;
|
H.x = SinTheta * cos( Phi );
|
||||||
|
H.y = SinTheta * sin( Phi );
|
||||||
// 距离衰减:通常使用平方衰减,但为避免分母为零,加一个小值
|
H.z = CosTheta;
|
||||||
float attenuation = 1.0 / (dist * dist + 0.0001);
|
vec3 UpVector = abs(N.z) < 0.999 ? vec3(0,0,1) : vec3(1,0,0);
|
||||||
|
vec3 TangentX = normalize( cross( UpVector, N ) );
|
||||||
// 可选:范围平滑衰减
|
vec3 TangentY = cross( N, TangentX );
|
||||||
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
|
// Tangent to world space
|
||||||
rangeFactor = rangeFactor * rangeFactor; // 平滑
|
return TangentX * H.x + TangentY * H.y + N * H.z;
|
||||||
attenuation *= rangeFactor;
|
|
||||||
|
|
||||||
vec3 Lh = normalize(L + params.View);
|
|
||||||
float cosLi = max(0.0, dot(params.Normal, L));
|
|
||||||
float cosLh = max(0.0, dot(params.Normal, Lh));
|
|
||||||
|
|
||||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View)));
|
|
||||||
float D = ndfGGX(cosLh, params.Roughness);
|
|
||||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
|
||||||
|
|
||||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
|
||||||
vec3 diffuseBRDF = kd * params.Albedo;
|
|
||||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
|
||||||
|
|
||||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 ComputeSpotLight(SpotLight light, vec3 F0, PBRParameters params, vec3 worldPos)
|
float TotalWeight = 0.0;
|
||||||
|
|
||||||
|
vec3 PrefilterEnvMap(float Roughness, vec3 R)
|
||||||
{
|
{
|
||||||
vec3 lightVec = light.Position - worldPos;
|
vec3 N = R;
|
||||||
float dist = length(lightVec);
|
vec3 V = R;
|
||||||
if (dist > light.Range) return vec3(0.0);
|
vec3 PrefilteredColor = vec3(0.0);
|
||||||
|
int NumSamples = 1024;
|
||||||
|
for(int i = 0; i < NumSamples; i++)
|
||||||
|
{
|
||||||
|
vec2 Xi = Hammersley(i, NumSamples);
|
||||||
|
vec3 H = ImportanceSampleGGX(Xi, Roughness, N);
|
||||||
|
vec3 L = 2 * dot(V, H) * H - V;
|
||||||
|
float NoL = clamp(dot(N, L), 0.0, 1.0);
|
||||||
|
if (NoL > 0)
|
||||||
|
{
|
||||||
|
PrefilteredColor += texture(u_EnvRadianceTex, L).rgb * NoL;
|
||||||
|
TotalWeight += NoL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PrefilteredColor / TotalWeight;
|
||||||
|
}
|
||||||
|
|
||||||
vec3 L = lightVec / dist;
|
// ---------------------------------------------------------------------------------------------------
|
||||||
vec3 Lradiance = light.Radiance * light.Intensity;
|
|
||||||
|
|
||||||
// 距离衰减
|
vec3 RotateVectorAboutY(float angle, vec3 vec)
|
||||||
float attenuation = 1.0 / (dist * dist + 0.0001);
|
{
|
||||||
float rangeFactor = clamp(1.0 - (dist / light.Range), 0.0, 1.0);
|
angle = radians(angle);
|
||||||
rangeFactor = rangeFactor * rangeFactor;
|
mat3x3 rotationMatrix ={vec3(cos(angle),0.0,sin(angle)),
|
||||||
attenuation *= rangeFactor;
|
vec3(0.0,1.0,0.0),
|
||||||
|
vec3(-sin(angle),0.0,cos(angle))};
|
||||||
// 角度衰减(聚光锥)
|
return rotationMatrix * vec;
|
||||||
float cosAngle = dot(-L, normalize(light.Direction)); // 光方向指向外,所以用 -L
|
|
||||||
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 + params.View);
|
|
||||||
float cosLi = max(0.0, dot(params.Normal, L));
|
|
||||||
float cosLh = max(0.0, dot(params.Normal, Lh));
|
|
||||||
|
|
||||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, params.View)));
|
|
||||||
float D = ndfGGX(cosLh, params.Roughness);
|
|
||||||
float G = GeometrySmith(params.Normal, params.View, L, params.Roughness);
|
|
||||||
|
|
||||||
vec3 kd = (1.0 - F) * (1.0 - params.Metalness);
|
|
||||||
vec3 diffuseBRDF = kd * params.Albedo;
|
|
||||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * params.NdotV);
|
|
||||||
|
|
||||||
return (diffuseBRDF + specularBRDF) * Lradiance * cosLi * attenuation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 Lighting(vec3 F0)
|
vec3 Lighting(vec3 F0)
|
||||||
@ -293,20 +246,22 @@ vec3 Lighting(vec3 F0)
|
|||||||
vec3 result = vec3(0.0);
|
vec3 result = vec3(0.0);
|
||||||
for(int i = 0; i < LightCount; i++)
|
for(int i = 0; i < LightCount; i++)
|
||||||
{
|
{
|
||||||
vec3 Li = u_DirectionalLights.Direction;
|
vec3 Li = -lights.Direction;
|
||||||
vec3 Lradiance = u_DirectionalLights.Radiance * u_DirectionalLights.Intensity;
|
vec3 Lradiance = lights.Radiance * lights.Multiplier;
|
||||||
vec3 Lh = normalize(Li + m_Params.View);
|
vec3 Lh = normalize(Li + m_Params.View);
|
||||||
|
|
||||||
|
// Calculate angles between surface normal and various light vectors.
|
||||||
float cosLi = max(0.0, dot(m_Params.Normal, Li));
|
float cosLi = max(0.0, dot(m_Params.Normal, Li));
|
||||||
float cosLh = max(0.0, dot(m_Params.Normal, Lh));
|
float cosLh = max(0.0, dot(m_Params.Normal, Lh));
|
||||||
|
|
||||||
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, m_Params.View)));
|
vec3 F = fresnelSchlick(F0, max(0.0, dot(Lh, m_Params.View)));
|
||||||
float D = ndfGGX(cosLh, m_Params.Roughness);
|
float D = ndfGGX(cosLh, m_Params.Roughness);
|
||||||
float G = GeometrySmith(m_Params.Normal, m_Params.View, Li, m_Params.Roughness);
|
float G = gaSchlickGGX(cosLi, m_Params.NdotV, m_Params.Roughness);
|
||||||
|
|
||||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||||
vec3 diffuseBRDF = kd * m_Params.Albedo;
|
vec3 diffuseBRDF = kd * m_Params.Albedo;
|
||||||
|
|
||||||
|
// Cook-Torrance
|
||||||
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * m_Params.NdotV);
|
vec3 specularBRDF = (F * D * G) / max(Epsilon, 4.0 * cosLi * m_Params.NdotV);
|
||||||
|
|
||||||
result += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
result += (diffuseBRDF + specularBRDF) * Lradiance * cosLi;
|
||||||
@ -314,109 +269,35 @@ vec3 Lighting(vec3 F0)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- IBL ----------
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 IBL(vec3 F0, vec3 Lr)
|
vec3 IBL(vec3 F0, vec3 Lr)
|
||||||
{
|
{
|
||||||
vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
|
vec3 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
|
||||||
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
|
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
|
||||||
|
// vec3 F = fresnelSchlickR(F0, m_Params.NdotV);
|
||||||
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||||
vec3 diffuseIBL = m_Params.Albedo * irradiance;
|
vec3 diffuseIBL = m_Params.Albedo * irradiance;
|
||||||
|
|
||||||
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
||||||
vec3 specularIrradiance = textureLod(
|
float NoV = clamp(m_Params.NdotV, 0.0, 1.0);
|
||||||
u_EnvRadianceTex,
|
vec3 R = 2.0 * dot(m_Params.View, m_Params.Normal) * m_Params.Normal - m_Params.View;
|
||||||
RotateVectorAboutY(u_EnvMapRotation, Lr),
|
vec3 specularIrradiance = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), (m_Params.Roughness) * u_EnvRadianceTexLevels).rgb;
|
||||||
m_Params.Roughness * u_EnvRadianceTexLevels
|
|
||||||
).rgb;
|
|
||||||
|
|
||||||
|
// Sample BRDF Lut, 1.0 - roughness for y-coord because texture was generated (in Sparky) for gloss model
|
||||||
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg;
|
vec2 specularBRDF = texture(u_BRDFLUTTexture, vec2(m_Params.NdotV, 1.0 - m_Params.Roughness)).rg;
|
||||||
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
||||||
|
|
||||||
return kd * diffuseIBL + specularIBL;
|
return kd * diffuseIBL + specularIBL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// shadow
|
|
||||||
|
|
||||||
float calculateShadow(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir)
|
|
||||||
{
|
|
||||||
// Perspective divide
|
|
||||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
|
||||||
|
|
||||||
// Transform to [0,1] range
|
|
||||||
projCoords = projCoords * 0.5 + 0.5;
|
|
||||||
|
|
||||||
// If outside shadow map bounds, assume no shadow
|
|
||||||
if(projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
// Get closest depth value from light's perspective
|
|
||||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
|
||||||
float currentDepth = projCoords.z;
|
|
||||||
|
|
||||||
// Calculate bias based on surface angle
|
|
||||||
float bias = max(u_ShadowBias * (1.0 - dot(normal, lightDir)), u_ShadowBias * 0.1);
|
|
||||||
|
|
||||||
// PCF (Percentage Closer Filtering) for soft shadows
|
|
||||||
float shadow = 0.0;
|
|
||||||
vec2 texelSize = 1.0 / textureSize(u_ShadowMap, 0);
|
|
||||||
int pcfRange = int(u_ShadowSoftness);
|
|
||||||
int sampleCount = 0;
|
|
||||||
|
|
||||||
for(int x = -pcfRange; x <= pcfRange; ++x)
|
|
||||||
{
|
|
||||||
for(int y = -pcfRange; y <= pcfRange; ++y)
|
|
||||||
{
|
|
||||||
float pcfDepth = texture(u_ShadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
|
|
||||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
|
||||||
sampleCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shadow /= float(sampleCount);
|
|
||||||
|
|
||||||
return shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
float ComputeShadow(vec4 fragPosLightSpace, float NdotL)
|
|
||||||
{
|
|
||||||
if (u_ShadowEnabled == 0) return 1.0;
|
|
||||||
|
|
||||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
|
||||||
projCoords = projCoords * 0.5 + 0.5;
|
|
||||||
|
|
||||||
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
|
|
||||||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
|
|
||||||
projCoords.z > 1.0) return 1.0;
|
|
||||||
|
|
||||||
float closestDepth = texture(u_ShadowMap, projCoords.xy).r;
|
|
||||||
float currentDepth = projCoords.z;
|
|
||||||
|
|
||||||
float bias = max(u_ShadowBias * (1.0 - NdotL), u_ShadowBias * 0.5);
|
|
||||||
|
|
||||||
float shadow = (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
|
|
||||||
return mix(1.0, 1.0 - u_ShadowIntensity, shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
|
// Standard PBR inputs
|
||||||
|
m_Params.Albedo = u_AlbedoTexToggle > 0.5 ? texture(u_AlbedoTexture, vs_Input.TexCoord).rgb : u_AlbedoColor;
|
||||||
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); // Minimum roughness of 0.05 to keep specular highlight
|
||||||
|
|
||||||
// normal
|
// Normals (either from vertex or map)
|
||||||
m_Params.Normal = normalize(vs_Input.Normal);
|
m_Params.Normal = normalize(vs_Input.Normal);
|
||||||
if (u_NormalTexToggle > 0.5)
|
if (u_NormalTexToggle > 0.5)
|
||||||
{
|
{
|
||||||
@ -426,32 +307,16 @@ void main()
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
// Specular reflection vector
|
||||||
vec3 Lr = 2.0 * m_Params.NdotV * m_Params.Normal - m_Params.View;
|
vec3 Lr = 2.0 * m_Params.NdotV * m_Params.Normal - m_Params.View;
|
||||||
|
|
||||||
|
// Fresnel reflectance, metals use albedo
|
||||||
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
||||||
|
|
||||||
// Shadow
|
vec3 lightContribution = Lighting(F0);
|
||||||
float shadowFactor = 1.0;
|
vec3 iblContribution = IBL(F0, Lr);
|
||||||
if (u_ShadowEnabled > 0.5) {
|
|
||||||
float shadow = calculateShadow(vs_Input.FragPosLightSpace, m_Params.Normal, u_DirectionalLights.Direction);
|
|
||||||
shadowFactor = 1.0 - shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
// directional light with with shadow
|
|
||||||
vec3 lightContribution = u_DirectionalLights.Intensity > 0.0 ? Lighting(F0) * shadowFactor : vec3(0.0);
|
|
||||||
|
|
||||||
if(u_PointLightCount > 0)
|
|
||||||
lightContribution += ComputePointLight(u_PointLights, F0, m_Params, vs_Input.WorldPosition);
|
|
||||||
|
|
||||||
if(u_SpotLightCount > 0)
|
|
||||||
lightContribution += ComputeSpotLight(u_SpotLights, F0, m_Params, vs_Input.WorldPosition);
|
|
||||||
|
|
||||||
vec3 iblContribution = IBL(F0, Lr) * u_IBLContribution;
|
|
||||||
|
|
||||||
color = vec4(lightContribution + iblContribution, 1.0);
|
color = vec4(lightContribution + iblContribution, 1.0);
|
||||||
|
// color = vec4(iblContribution, 1.0);
|
||||||
// Bloom
|
|
||||||
float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
|
|
||||||
o_BloomColor = brightness > u_BloomThreshold ? color : vec4(0.0, 0.0, 0.0, 1.0);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,159 +0,0 @@
|
|||||||
#type compute
|
|
||||||
#version 450 core
|
|
||||||
|
|
||||||
const float PI = 3.141592;
|
|
||||||
|
|
||||||
layout(binding = 0, rgba32f) restrict writeonly uniform imageCube o_CubeMap;
|
|
||||||
|
|
||||||
uniform vec3 u_TurbidityAzimuthInclination;
|
|
||||||
|
|
||||||
#define PI 3.14159265359
|
|
||||||
|
|
||||||
vec3 GetCubeMapTexCoord()
|
|
||||||
{
|
|
||||||
vec2 st = gl_GlobalInvocationID.xy / vec2(imageSize(o_CubeMap));
|
|
||||||
vec2 uv = 2.0 * vec2(st.x, 1.0 - st.y) - vec2(1.0);
|
|
||||||
|
|
||||||
vec3 ret;
|
|
||||||
if (gl_GlobalInvocationID.z == 0) ret = vec3( 1.0, uv.y, -uv.x);
|
|
||||||
else if (gl_GlobalInvocationID.z == 1) ret = vec3( -1.0, uv.y, uv.x);
|
|
||||||
else if (gl_GlobalInvocationID.z == 2) ret = vec3( uv.x, 1.0, -uv.y);
|
|
||||||
else if (gl_GlobalInvocationID.z == 3) ret = vec3( uv.x, -1.0, uv.y);
|
|
||||||
else if (gl_GlobalInvocationID.z == 4) ret = vec3( uv.x, uv.y, 1.0);
|
|
||||||
else if (gl_GlobalInvocationID.z == 5) ret = vec3(-uv.x, uv.y, -1.0);
|
|
||||||
return normalize(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
float saturatedDot( in vec3 a, in vec3 b )
|
|
||||||
{
|
|
||||||
return clamp(dot(a, b), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 YxyToXYZ( in vec3 Yxy )
|
|
||||||
{
|
|
||||||
float Y = Yxy.r;
|
|
||||||
float x = Yxy.g;
|
|
||||||
float y = Yxy.b;
|
|
||||||
|
|
||||||
float X = x * ( Y / y );
|
|
||||||
float Z = ( 1.0 - x - y ) * ( Y / y );
|
|
||||||
|
|
||||||
return vec3(X,Y,Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 XYZToRGB( in vec3 XYZ )
|
|
||||||
{
|
|
||||||
// CIE/E
|
|
||||||
mat3 M = mat3
|
|
||||||
(
|
|
||||||
2.3706743, -0.9000405, -0.4706338,
|
|
||||||
-0.5138850, 1.4253036, 0.0885814,
|
|
||||||
0.0052982, -0.0146949, 1.0093968
|
|
||||||
);
|
|
||||||
|
|
||||||
return XYZ * M;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vec3 YxyToRGB( in vec3 Yxy )
|
|
||||||
{
|
|
||||||
vec3 XYZ = YxyToXYZ( Yxy );
|
|
||||||
vec3 RGB = XYZToRGB( XYZ );
|
|
||||||
return RGB;
|
|
||||||
}
|
|
||||||
|
|
||||||
void calculatePerezDistribution( in float t, out vec3 A, out vec3 B, out vec3 C, out vec3 D, out vec3 E )
|
|
||||||
{
|
|
||||||
A = vec3( 0.1787 * t - 1.4630, -0.0193 * t - 0.2592, -0.0167 * t - 0.2608 );
|
|
||||||
B = vec3( -0.3554 * t + 0.4275, -0.0665 * t + 0.0008, -0.0950 * t + 0.0092 );
|
|
||||||
C = vec3( -0.0227 * t + 5.3251, -0.0004 * t + 0.2125, -0.0079 * t + 0.2102 );
|
|
||||||
D = vec3( 0.1206 * t - 2.5771, -0.0641 * t - 0.8989, -0.0441 * t - 1.6537 );
|
|
||||||
E = vec3( -0.0670 * t + 0.3703, -0.0033 * t + 0.0452, -0.0109 * t + 0.0529 );
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculateZenithLuminanceYxy( in float t, in float thetaS )
|
|
||||||
{
|
|
||||||
float chi = ( 4.0 / 9.0 - t / 120.0 ) * ( PI - 2.0 * thetaS );
|
|
||||||
float Yz = ( 4.0453 * t - 4.9710 ) * tan( chi ) - 0.2155 * t + 2.4192;
|
|
||||||
|
|
||||||
float theta2 = thetaS * thetaS;
|
|
||||||
float theta3 = theta2 * thetaS;
|
|
||||||
float T = t;
|
|
||||||
float T2 = t * t;
|
|
||||||
|
|
||||||
float xz =
|
|
||||||
( 0.00165 * theta3 - 0.00375 * theta2 + 0.00209 * thetaS + 0.0) * T2 +
|
|
||||||
(-0.02903 * theta3 + 0.06377 * theta2 - 0.03202 * thetaS + 0.00394) * T +
|
|
||||||
( 0.11693 * theta3 - 0.21196 * theta2 + 0.06052 * thetaS + 0.25886);
|
|
||||||
|
|
||||||
float yz =
|
|
||||||
( 0.00275 * theta3 - 0.00610 * theta2 + 0.00317 * thetaS + 0.0) * T2 +
|
|
||||||
(-0.04214 * theta3 + 0.08970 * theta2 - 0.04153 * thetaS + 0.00516) * T +
|
|
||||||
( 0.15346 * theta3 - 0.26756 * theta2 + 0.06670 * thetaS + 0.26688);
|
|
||||||
|
|
||||||
return vec3( Yz, xz, yz );
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculatePerezLuminanceYxy( in float theta, in float gamma, in vec3 A, in vec3 B, in vec3 C, in vec3 D, in vec3 E )
|
|
||||||
{
|
|
||||||
float cosTheta = max(cos(theta), 1e-6);
|
|
||||||
return ( 1.0 + A * exp( B / cos( theta ) ) ) * ( 1.0 + C * exp( D * gamma ) + E * cos( gamma ) * cos( gamma ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 calculateSkyLuminanceRGB( in vec3 s, in vec3 e, in float t )
|
|
||||||
{
|
|
||||||
vec3 A, B, C, D, E;
|
|
||||||
calculatePerezDistribution( t, A, B, C, D, E );
|
|
||||||
|
|
||||||
float thetaS = acos(clamp(dot(s, vec3(0,1,0)), 0.0, 1.0));
|
|
||||||
float thetaE = acos(clamp(dot(e, vec3(0,1,0)), 0.0, 1.0));
|
|
||||||
float gammaE = acos( saturatedDot( s, e ) );
|
|
||||||
|
|
||||||
vec3 Yz = calculateZenithLuminanceYxy( t, thetaS );
|
|
||||||
|
|
||||||
vec3 fThetaGamma = calculatePerezLuminanceYxy( thetaE, gammaE, A, B, C, D, E );
|
|
||||||
vec3 fZeroThetaS = calculatePerezLuminanceYxy( 0.0, thetaS, A, B, C, D, E );
|
|
||||||
|
|
||||||
vec3 Yp = Yz * ( fThetaGamma / fZeroThetaS );
|
|
||||||
|
|
||||||
return YxyToRGB( Yp );
|
|
||||||
}
|
|
||||||
|
|
||||||
layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
vec3 cubeTC = GetCubeMapTexCoord();
|
|
||||||
|
|
||||||
float turbidity = u_TurbidityAzimuthInclination.x;
|
|
||||||
float azimuth = u_TurbidityAzimuthInclination.y;;
|
|
||||||
float inclination = u_TurbidityAzimuthInclination.z;
|
|
||||||
vec3 sunDir = normalize( vec3( sin(inclination) * cos(azimuth), cos(inclination), sin(inclination) * sin(azimuth) ) );
|
|
||||||
vec3 viewDir = cubeTC;
|
|
||||||
|
|
||||||
const float SUN_ANGULAR_RADIUS = 0.03465;
|
|
||||||
const float SUN_INTENSITY = 100.0;
|
|
||||||
vec3 skyLuminance;
|
|
||||||
|
|
||||||
if (viewDir.y < 0.0) {
|
|
||||||
skyLuminance = vec3(0.02);
|
|
||||||
} else {
|
|
||||||
skyLuminance = calculateSkyLuminanceRGB(sunDir, viewDir, turbidity);
|
|
||||||
}
|
|
||||||
|
|
||||||
float cosAngle = dot(viewDir, sunDir);
|
|
||||||
float angle = acos(cosAngle);
|
|
||||||
if (angle < SUN_ANGULAR_RADIUS) {
|
|
||||||
skyLuminance = vec3(SUN_INTENSITY);
|
|
||||||
} else {
|
|
||||||
float haloWidth = 0.1;
|
|
||||||
if (angle < SUN_ANGULAR_RADIUS + haloWidth) {
|
|
||||||
float t = (angle - SUN_ANGULAR_RADIUS) / haloWidth;
|
|
||||||
float haloFactor = 1.0 - smoothstep(0.0, 1.0, t);
|
|
||||||
skyLuminance += vec3(SUN_INTENSITY * 0.1 * haloFactor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 color = vec4(skyLuminance * 0.05, 1.0);
|
|
||||||
imageStore(o_CubeMap, ivec3(gl_GlobalInvocationID), color);
|
|
||||||
}
|
|
||||||
@ -6,14 +6,14 @@
|
|||||||
layout(location = 0) in vec3 a_Position;
|
layout(location = 0) in vec3 a_Position;
|
||||||
layout(location = 1) in vec4 a_Color;
|
layout(location = 1) in vec4 a_Color;
|
||||||
layout(location = 2) in vec2 a_TexCoord;
|
layout(location = 2) in vec2 a_TexCoord;
|
||||||
layout(location = 3) in int a_TexIndex;
|
layout(location = 3) in float a_TexIndex;
|
||||||
layout(location = 4) in float a_TilingFactor;
|
layout(location = 4) in float a_TilingFactor;
|
||||||
|
|
||||||
uniform mat4 u_ViewProjection;
|
uniform mat4 u_ViewProjection;
|
||||||
|
|
||||||
out vec4 v_Color;
|
out vec4 v_Color;
|
||||||
out vec2 v_TexCoord;
|
out vec2 v_TexCoord;
|
||||||
flat out int v_TexIndex;
|
out float v_TexIndex;
|
||||||
out float v_TilingFactor;
|
out float v_TilingFactor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
@ -32,17 +32,12 @@ layout(location = 0) out vec4 color;
|
|||||||
|
|
||||||
in vec4 v_Color;
|
in vec4 v_Color;
|
||||||
in vec2 v_TexCoord;
|
in vec2 v_TexCoord;
|
||||||
flat in int v_TexIndex;
|
in float v_TexIndex;
|
||||||
in float v_TilingFactor;
|
in float v_TilingFactor;
|
||||||
|
|
||||||
uniform sampler2D u_Textures[32];
|
uniform sampler2D u_Textures[32];
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 texColor = texture(u_Textures[v_TexIndex], v_TexCoord * v_TilingFactor) * v_Color;
|
color = texture(u_Textures[int(v_TexIndex)], v_TexCoord * v_TilingFactor) * v_Color;
|
||||||
|
|
||||||
if(texColor.a < 0.1)
|
|
||||||
discard;
|
|
||||||
|
|
||||||
color = texColor;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
// Basic Texture Shader
|
|
||||||
|
|
||||||
#type vertex
|
|
||||||
#version 430 core
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_WorldPosition;
|
|
||||||
layout(location = 1) in float a_Thickness;
|
|
||||||
layout(location = 2) in vec2 a_LocalPosition;
|
|
||||||
layout(location = 3) in vec4 a_Color;
|
|
||||||
uniform mat4 u_ViewProjection;
|
|
||||||
|
|
||||||
out vec2 v_LocalPosition;
|
|
||||||
out float v_Thickness;
|
|
||||||
out vec4 v_Color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
v_LocalPosition = a_LocalPosition;
|
|
||||||
v_Thickness = a_Thickness;
|
|
||||||
v_Color = a_Color;
|
|
||||||
gl_Position = u_ViewProjection * vec4(a_WorldPosition, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#type fragment
|
|
||||||
#version 430 core
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 color;
|
|
||||||
|
|
||||||
in vec2 v_LocalPosition;
|
|
||||||
in float v_Thickness;
|
|
||||||
in vec4 v_Color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
float fade = 0.01;
|
|
||||||
float dist = sqrt(dot(v_LocalPosition, v_LocalPosition));
|
|
||||||
if (dist > 1.0 || dist < 1.0 - v_Thickness - fade)
|
|
||||||
discard;
|
|
||||||
|
|
||||||
float alpha = 1.0 - smoothstep(1.0f - fade, 1.0f, dist);
|
|
||||||
alpha *= smoothstep(1.0 - v_Thickness - fade, 1.0 - v_Thickness, dist);
|
|
||||||
color = v_Color;
|
|
||||||
color.a = alpha;
|
|
||||||
}
|
|
||||||
@ -17,53 +17,20 @@ 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 sampler2DMS u_Texture;
|
uniform sampler2DMS u_Texture;
|
||||||
uniform sampler2D u_BloomTexture;
|
uniform float u_Exposure;
|
||||||
|
|
||||||
|
|
||||||
uniform bool u_EnableAutoExposure;
|
|
||||||
uniform float u_ManualExposure;
|
|
||||||
layout(std430, binding = 2) buffer Exposure
|
|
||||||
{
|
|
||||||
float u_Exposure;
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform int u_TextureSamples;
|
uniform int u_TextureSamples;
|
||||||
|
|
||||||
uniform bool u_EnableBloom;
|
vec4 MultiSampleTexture(sampler2DMS tex, ivec2 texCoord, int samples)
|
||||||
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);
|
vec4 result = vec4(0.0);
|
||||||
for (int i = 0; i < u_TextureSamples; i++)
|
for (int i = 0; i < samples; i++)
|
||||||
result += texelFetch(tex, texCoord, i);
|
result += texelFetch(tex, texCoord, i);
|
||||||
|
|
||||||
result /= float(u_TextureSamples);
|
result /= float(samples);
|
||||||
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,20 +39,10 @@ void main()
|
|||||||
const float gamma = 2.2;
|
const float gamma = 2.2;
|
||||||
const float pureWhite = 1.0;
|
const float pureWhite = 1.0;
|
||||||
|
|
||||||
// Tonemapping
|
ivec2 texSize = textureSize(u_Texture);
|
||||||
vec4 msColor = MultiSampleTexture(u_Texture, v_TexCoord);
|
ivec2 texCoord = ivec2(v_TexCoord * texSize);
|
||||||
vec3 color = msColor.rgb;
|
vec4 msColor = MultiSampleTexture(u_Texture, texCoord, u_TextureSamples);
|
||||||
|
vec3 color = msColor.rgb * u_Exposure;//texture(u_Texture, v_TexCoord).rgb * u_Exposure;
|
||||||
if (u_EnableBloom)
|
|
||||||
{
|
|
||||||
vec3 bloomColor = texture(u_BloomTexture, v_TexCoord).rgb;
|
|
||||||
color += bloomColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(u_EnableAutoExposure)
|
|
||||||
color *= u_Exposure;
|
|
||||||
else
|
|
||||||
color *= u_ManualExposure;
|
|
||||||
|
|
||||||
// Reinhard tonemapping operator.
|
// Reinhard tonemapping operator.
|
||||||
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
|
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
|
||||||
@ -97,8 +54,4 @@ void main()
|
|||||||
|
|
||||||
// Gamma correction.
|
// 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);
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
// Shadow Map shader
|
|
||||||
|
|
||||||
#type vertex
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
|
||||||
|
|
||||||
uniform mat4 u_LightViewProjection;
|
|
||||||
uniform mat4 u_Transform;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
gl_Position = u_LightViewProjection * u_Transform * vec4(a_Position, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#type fragment
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
// Shadow Map shader
|
|
||||||
|
|
||||||
#type vertex
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
|
||||||
|
|
||||||
layout(location = 5) in ivec4 a_BoneIndices;
|
|
||||||
layout(location = 6) in vec4 a_BoneWeights;
|
|
||||||
|
|
||||||
uniform mat4 u_LightViewProjection;
|
|
||||||
uniform mat4 u_Transform;
|
|
||||||
|
|
||||||
const int MAX_BONES = 100;
|
|
||||||
uniform mat4 u_BoneTransforms[100];
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
mat4 boneTransform = u_BoneTransforms[a_BoneIndices[0]] * a_BoneWeights[0];
|
|
||||||
boneTransform += u_BoneTransforms[a_BoneIndices[1]] * a_BoneWeights[1];
|
|
||||||
boneTransform += u_BoneTransforms[a_BoneIndices[2]] * a_BoneWeights[2];
|
|
||||||
boneTransform += u_BoneTransforms[a_BoneIndices[3]] * a_BoneWeights[3];
|
|
||||||
|
|
||||||
vec4 localPosition = boneTransform * vec4(a_Position, 1.0);
|
|
||||||
gl_Position = u_LightViewProjection * u_Transform * localPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
#type fragment
|
|
||||||
#version 430
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@ -24,13 +24,10 @@ layout(location = 0) out vec4 finalColor;
|
|||||||
|
|
||||||
uniform samplerCube u_Texture;
|
uniform samplerCube u_Texture;
|
||||||
uniform float u_TextureLod;
|
uniform float u_TextureLod;
|
||||||
uniform float u_SkyIntensity;
|
|
||||||
|
|
||||||
in vec3 v_Position;
|
in vec3 v_Position;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 color = textureLod(u_Texture, v_Position, u_TextureLod).rgb * u_SkyIntensity;
|
finalColor = textureLod(u_Texture, v_Position, u_TextureLod);
|
||||||
finalColor = vec4(color, 1.0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
108
Editor/imgui.ini
@ -1,108 +0,0 @@
|
|||||||
[Window][DockSpace Demo]
|
|
||||||
Pos=0,0
|
|
||||||
Size=1920,1080
|
|
||||||
Collapsed=0
|
|
||||||
|
|
||||||
[Window][Debug##Default]
|
|
||||||
Pos=60,60
|
|
||||||
Size=400,400
|
|
||||||
Collapsed=0
|
|
||||||
|
|
||||||
[Window][Scene Hierarchy]
|
|
||||||
Pos=1449,24
|
|
||||||
Size=471,385
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000009,0
|
|
||||||
|
|
||||||
[Window][Properties]
|
|
||||||
Pos=1449,411
|
|
||||||
Size=471,669
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x0000000A,0
|
|
||||||
|
|
||||||
[Window][Scene Renderer]
|
|
||||||
Pos=0,585
|
|
||||||
Size=481,495
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000006,0
|
|
||||||
|
|
||||||
[Window][Materials]
|
|
||||||
Pos=0,24
|
|
||||||
Size=481,559
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000005,0
|
|
||||||
|
|
||||||
[Window][Script Engine Debug]
|
|
||||||
Pos=1449,411
|
|
||||||
Size=471,669
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x0000000A,2
|
|
||||||
|
|
||||||
[Window][Model]
|
|
||||||
Pos=1595,454
|
|
||||||
Size=471,744
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x0000000A,3
|
|
||||||
|
|
||||||
[Window][Toolbar]
|
|
||||||
Pos=483,24
|
|
||||||
Size=1110,32
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000001,0
|
|
||||||
|
|
||||||
[Window][Viewport]
|
|
||||||
Pos=483,58
|
|
||||||
Size=964,647
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x0000000B,0
|
|
||||||
|
|
||||||
[Window][Environment]
|
|
||||||
Pos=1449,411
|
|
||||||
Size=471,669
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x0000000A,1
|
|
||||||
|
|
||||||
[Window][Project]
|
|
||||||
Pos=483,707
|
|
||||||
Size=964,373
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x0000000C,0
|
|
||||||
|
|
||||||
[Window][Objects]
|
|
||||||
Pos=483,707
|
|
||||||
Size=964,373
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x0000000C,1
|
|
||||||
|
|
||||||
[Window][Physics]
|
|
||||||
Pos=189,113
|
|
||||||
Size=468,371
|
|
||||||
Collapsed=0
|
|
||||||
|
|
||||||
[Window][##tool_bar]
|
|
||||||
Pos=483,24
|
|
||||||
Size=964,32
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x00000001,0
|
|
||||||
|
|
||||||
[Window][Console]
|
|
||||||
Pos=483,707
|
|
||||||
Size=964,373
|
|
||||||
Collapsed=0
|
|
||||||
DockId=0x0000000C,2
|
|
||||||
|
|
||||||
[Docking][Data]
|
|
||||||
DockSpace ID=0xC0DFADC4 Window=0xD0388BC8 Pos=268,189 Size=1920,1056 Split=X Selected=0x0C01D6D5
|
|
||||||
DockNode ID=0x00000007 Parent=0xC0DFADC4 SizeRef=1557,1542 Split=X
|
|
||||||
DockNode ID=0x00000003 Parent=0x00000007 SizeRef=481,1542 Split=Y Selected=0x5D711C2C
|
|
||||||
DockNode ID=0x00000005 Parent=0x00000003 SizeRef=481,817 Selected=0x5D711C2C
|
|
||||||
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=481,723 Selected=0x68D924E0
|
|
||||||
DockNode ID=0x00000004 Parent=0x00000007 SizeRef=1074,1542 Split=Y
|
|
||||||
DockNode ID=0x00000001 Parent=0x00000004 SizeRef=2560,32 CentralNode=1 HiddenTabBar=1 Selected=0xE8CD5B84
|
|
||||||
DockNode ID=0x00000002 Parent=0x00000004 SizeRef=2560,1508 Split=Y Selected=0xC450F867
|
|
||||||
DockNode ID=0x0000000B Parent=0x00000002 SizeRef=1401,955 HiddenTabBar=1 Selected=0xC450F867
|
|
||||||
DockNode ID=0x0000000C Parent=0x00000002 SizeRef=1401,551 Selected=0x9C21DE82
|
|
||||||
DockNode ID=0x00000008 Parent=0xC0DFADC4 SizeRef=471,1542 Split=Y Selected=0x8C72BEA8
|
|
||||||
DockNode ID=0x00000009 Parent=0x00000008 SizeRef=315,563 Selected=0xB8729153
|
|
||||||
DockNode ID=0x0000000A Parent=0x00000008 SizeRef=315,977 Selected=0x73E3D51F
|
|
||||||
|
|
||||||
@ -4,7 +4,6 @@
|
|||||||
<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>
|
||||||
|
|||||||
@ -5,7 +5,6 @@ namespace Example
|
|||||||
public class BasicController : Entity
|
public class BasicController : Entity
|
||||||
{
|
{
|
||||||
public float Speed;
|
public float Speed;
|
||||||
public float DistanceFromPlayer = 20.0F;
|
|
||||||
|
|
||||||
private Entity m_PlayerEntity;
|
private Entity m_PlayerEntity;
|
||||||
|
|
||||||
@ -16,17 +15,13 @@ namespace Example
|
|||||||
|
|
||||||
public void OnUpdate(float ts)
|
public void OnUpdate(float ts)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
Mat4 transform = GetTransform();
|
Mat4 transform = GetTransform();
|
||||||
|
|
||||||
Vec3 playerTranstation = m_PlayerEntity.GetTransform().Translation;
|
|
||||||
Vec3 translation = transform.Translation;
|
Vec3 translation = transform.Translation;
|
||||||
translation.XY = playerTranstation.XY;
|
translation.XY = m_PlayerEntity.GetTransform().Translation.XY;
|
||||||
translation.Z = playerTranstation.Z + DistanceFromPlayer;
|
|
||||||
translation.Y = Math.Max(translation.Y, 4.5f);
|
translation.Y = Math.Max(translation.Y, 4.5f);
|
||||||
transform.Translation = translation;
|
transform.Translation = translation;
|
||||||
SetTransform(transform);
|
SetTransform(transform);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,223 +0,0 @@
|
|||||||
using System.Runtime.InteropServices;
|
|
||||||
using Prism;
|
|
||||||
|
|
||||||
namespace FPSExample
|
|
||||||
{
|
|
||||||
public class FPSPlayer : Entity
|
|
||||||
{
|
|
||||||
public float WalkingSpeed = 10.0f;
|
|
||||||
public float RunSpeed = 20.0f;
|
|
||||||
public float JumpForce = 50.0f;
|
|
||||||
|
|
||||||
public float m_Radius = 0.5f;
|
|
||||||
public float TorqueStrength = 10.0f;
|
|
||||||
|
|
||||||
[NonSerialized]
|
|
||||||
public float MouseSensitivity = 10.0f;
|
|
||||||
|
|
||||||
public float CameraForwardOffset = 0.5f;
|
|
||||||
public float CameraYOffset = 0.5f;
|
|
||||||
|
|
||||||
private bool m_Colliding = false;
|
|
||||||
private float m_CurrentSpeed;
|
|
||||||
|
|
||||||
private RigidBodyComponent m_RigidBody;
|
|
||||||
private TransformComponent m_Transform;
|
|
||||||
private TransformComponent m_CameraTransform;
|
|
||||||
|
|
||||||
private Entity m_CameraEntity;
|
|
||||||
|
|
||||||
private Vec2 m_LastMousePosition;
|
|
||||||
private float m_CurrentYMovement = 0.0f;
|
|
||||||
|
|
||||||
private Vec2 m_MovementDirection = new Vec2(0.0f);
|
|
||||||
private bool m_ShouldJump = false;
|
|
||||||
|
|
||||||
void OnCreate()
|
|
||||||
{
|
|
||||||
m_Transform = GetComponent<TransformComponent>();
|
|
||||||
m_RigidBody = GetComponent<RigidBodyComponent>();
|
|
||||||
|
|
||||||
m_CurrentSpeed = WalkingSpeed;
|
|
||||||
|
|
||||||
AddCollisionBeginCallback((n) => { m_Colliding = true; });
|
|
||||||
AddCollisionEndCallback((n) => { m_Colliding = false; });
|
|
||||||
|
|
||||||
m_CameraEntity = FindEntityByTag("Camera");
|
|
||||||
|
|
||||||
m_CameraTransform = m_CameraEntity.GetComponent<TransformComponent>();
|
|
||||||
m_LastMousePosition = Input.GetMousePosition();
|
|
||||||
|
|
||||||
Input.SetCursorMode(Input.CursorMode.Locked);
|
|
||||||
|
|
||||||
int size = Marshal.SizeOf<Transform>();
|
|
||||||
Console.WriteLine($"C# size of Transform: {size}");
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnUpdate(float ts)
|
|
||||||
{
|
|
||||||
if (Input.IsKeyPressed(KeyCode.Escape) && Input.GetCursorMode() == Input.CursorMode.Locked)
|
|
||||||
Input.SetCursorMode(Input.CursorMode.Normal);
|
|
||||||
|
|
||||||
if(Input.IsMouseButtonPressed(Input.MouseButton.Left) && Input.GetCursorMode() == Input.CursorMode.Normal)
|
|
||||||
Input.SetCursorMode(Input.CursorMode.Locked);
|
|
||||||
|
|
||||||
m_CurrentSpeed = Input.IsKeyPressed(KeyCode.LeftControl) ? RunSpeed : WalkingSpeed;
|
|
||||||
|
|
||||||
|
|
||||||
UpdateRayCasting();
|
|
||||||
UpdateMovementInput();
|
|
||||||
UpdateRotation(ts);
|
|
||||||
UpdateCameraTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPhysicsUpdate(float fixedTimeStep)
|
|
||||||
{
|
|
||||||
UpdateMovement();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateRotation(float ts)
|
|
||||||
{
|
|
||||||
Vec2 currentMousePosition = Input.GetMousePosition();
|
|
||||||
Vec2 delta = m_LastMousePosition - currentMousePosition;
|
|
||||||
|
|
||||||
m_CurrentYMovement = delta.X * MouseSensitivity * ts;
|
|
||||||
float xRotation = delta.Y * MouseSensitivity * ts;
|
|
||||||
// m_RigidBody.Rotate(new Vec3(0.0f, m_CurrentYMovement, 0.0f));
|
|
||||||
|
|
||||||
if (delta.X != 0 || delta.Y != 0)
|
|
||||||
{
|
|
||||||
m_CameraTransform.Rotation += new Vec3(xRotation, m_CurrentYMovement, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_CameraTransform.Rotation = new Vec3(Mathf.Clamp(m_CameraTransform.Rotation.X, -89.0f, 89.0f), m_CameraTransform.Rotation.YZ);
|
|
||||||
|
|
||||||
m_LastMousePosition = currentMousePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateMovementInput()
|
|
||||||
{
|
|
||||||
if (Input.IsKeyPressed(KeyCode.W)){
|
|
||||||
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
|
|
||||||
m_MovementDirection.Y = 0.0f;
|
|
||||||
|
|
||||||
if(Input.IsKeyPressed(KeyCode.A)){
|
|
||||||
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
|
|
||||||
m_MovementDirection.X = 0.0f;
|
|
||||||
|
|
||||||
m_ShouldJump = Input.IsKeyPressed(KeyCode.Space) && !m_ShouldJump;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collider[] colliders = new Collider[10];
|
|
||||||
|
|
||||||
private void UpdateRayCasting()
|
|
||||||
{
|
|
||||||
RaycastHit hitInfo;
|
|
||||||
if (Input.IsKeyPressed(KeyCode.H) &&
|
|
||||||
Physics.Raycast(m_CameraTransform.Translation + (m_CameraTransform.Transform.Forward),
|
|
||||||
m_CameraTransform.Transform.Forward, 20.0f, out hitInfo))
|
|
||||||
{
|
|
||||||
FindEntityByID(hitInfo.EntityID).GetComponent<MeshComponent>().Mesh.GetMaterial(0).Set("u_AlbedoColor", new Vec3(1.0f ,0.0f, 0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Input.IsKeyPressed(KeyCode.I))
|
|
||||||
{
|
|
||||||
// NOTE: The NonAlloc version of Overlap functions should be used when possible since it doesn't allocate a new array
|
|
||||||
// whenever you call it. The normal versions allocates a brand new array every time.
|
|
||||||
|
|
||||||
int numColliders = Physics.OverlapBoxNonAlloc(m_Transform.Translation, new Vec3(1.0f), colliders);
|
|
||||||
|
|
||||||
Console.WriteLine("Colliders: {0}", numColliders);
|
|
||||||
// When using NonAlloc it's not safe to use a foreach loop since some of the colliders may not exist
|
|
||||||
for (int i = 0; i < numColliders; i++)
|
|
||||||
{
|
|
||||||
Console.WriteLine(colliders[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void UpdateMovement()
|
|
||||||
{
|
|
||||||
// 2. 计算期望的移动方向(世界坐标系)
|
|
||||||
Vec3 desiredDirection = Vec3.Zero;
|
|
||||||
|
|
||||||
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();
|
|
||||||
Vec3 velocity = movement * m_CurrentSpeed;
|
|
||||||
velocity.Y = m_RigidBody.GetLinearVelocity().Y;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
Debug.Log("Jump");
|
|
||||||
m_RigidBody.AddForce(Vec3.Up * JumpForce, RigidBodyComponent.ForceMode.Impulse);
|
|
||||||
m_ShouldJump = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateCameraTransform(){
|
|
||||||
Vec3 position = m_Transform.Translation + m_CameraTransform.Transform.Forward * CameraForwardOffset;
|
|
||||||
position.Y += CameraYOffset;
|
|
||||||
m_CameraTransform.Translation = position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -78,7 +78,6 @@ namespace Example
|
|||||||
|
|
||||||
void OnUpdate(float ts)
|
void OnUpdate(float ts)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
Mat4 transform = GetTransform();
|
Mat4 transform = GetTransform();
|
||||||
Vec3 translation = transform.Translation;
|
Vec3 translation = transform.Translation;
|
||||||
translation.Y += ts * speed;
|
translation.Y += ts * speed;
|
||||||
@ -92,7 +91,6 @@ namespace Example
|
|||||||
transform.Translation = translation;
|
transform.Translation = translation;
|
||||||
|
|
||||||
SetTransform(transform);
|
SetTransform(transform);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -72,11 +72,9 @@ namespace Example
|
|||||||
|
|
||||||
if (Input.IsKeyPressed(KeyCode.R))
|
if (Input.IsKeyPressed(KeyCode.R))
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
Mat4 transform = GetTransform();
|
Mat4 transform = GetTransform();
|
||||||
transform.Translation = new Vec3(0.0f);
|
transform.Translation = new Vec3(0.0f);
|
||||||
SetTransform(transform);
|
SetTransform(transform);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,104 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
using Prism;
|
|
||||||
|
|
||||||
namespace Example
|
|
||||||
{
|
|
||||||
class PlayerSphere : Entity
|
|
||||||
{
|
|
||||||
public float HorizontalForce = 10.0f;
|
|
||||||
public float JumpForce = 10.0f;
|
|
||||||
|
|
||||||
private RigidBodyComponent m_PhysicsBody;
|
|
||||||
private MaterialInstance m_MeshMaterial;
|
|
||||||
|
|
||||||
public int m_CollisionCounter = 0;
|
|
||||||
|
|
||||||
public Vec3 MaxSpeed = new Vec3();
|
|
||||||
|
|
||||||
private bool Colliding => m_CollisionCounter > 0;
|
|
||||||
|
|
||||||
private TransformComponent m_Transform;
|
|
||||||
void OnCreate()
|
|
||||||
{
|
|
||||||
m_PhysicsBody = GetComponent<RigidBodyComponent>();
|
|
||||||
m_Transform = GetComponent<TransformComponent>();
|
|
||||||
|
|
||||||
MeshComponent meshComponent = GetComponent<MeshComponent>();
|
|
||||||
m_MeshMaterial = meshComponent.Mesh.GetMaterial(0);
|
|
||||||
m_MeshMaterial.Set("u_Metalness", 0.0f);
|
|
||||||
|
|
||||||
AddCollisionBeginCallback(OnPlayerCollisionBegin);
|
|
||||||
AddCollisionEndCallback(OnPlayerCollisionEnd);
|
|
||||||
AddTriggerBeginCallback(OnPlayerTriggerBegin);
|
|
||||||
AddTriggerEndCallback(OnPlayerTriggerEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPlayerCollisionBegin(float value)
|
|
||||||
{
|
|
||||||
m_CollisionCounter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPlayerCollisionEnd(float value)
|
|
||||||
{
|
|
||||||
m_CollisionCounter--;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPlayerTriggerBegin(float value)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Player trigger begin");
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPlayerTriggerEnd(float value)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Player trigger end");
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnUpdate(float ts)
|
|
||||||
{
|
|
||||||
float movementForce = HorizontalForce;
|
|
||||||
|
|
||||||
if (!Colliding)
|
|
||||||
{
|
|
||||||
movementForce *= 0.4f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Input.IsKeyPressed(KeyCode.W))
|
|
||||||
m_PhysicsBody.AddForce(m_Transform.Transform.Forward * movementForce);
|
|
||||||
else if (Input.IsKeyPressed(KeyCode.S))
|
|
||||||
m_PhysicsBody.AddForce(m_Transform.Transform.Forward * -movementForce);
|
|
||||||
|
|
||||||
if (Input.IsKeyPressed(KeyCode.D))
|
|
||||||
m_PhysicsBody.AddForce(m_Transform.Transform.Right * movementForce);
|
|
||||||
else if (Input.IsKeyPressed(KeyCode.A))
|
|
||||||
m_PhysicsBody.AddForce(m_Transform.Transform.Right * -movementForce);
|
|
||||||
|
|
||||||
if (Colliding && Input.IsKeyPressed(KeyCode.Space))
|
|
||||||
m_PhysicsBody.AddForce(m_Transform.Transform.Up * JumpForce);
|
|
||||||
|
|
||||||
if (Colliding)
|
|
||||||
m_MeshMaterial.Set("u_AlbedoColor", new Vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
else
|
|
||||||
m_MeshMaterial.Set("u_AlbedoColor", new Vec3(0.8f, 0.8f, 0.8f));
|
|
||||||
|
|
||||||
Vec3 linearVelocity = m_PhysicsBody.GetLinearVelocity();
|
|
||||||
linearVelocity.Clamp(new Vec3(-MaxSpeed.X, -1000, -MaxSpeed.Z), MaxSpeed);
|
|
||||||
m_PhysicsBody.SetLinearVelocity(linearVelocity);
|
|
||||||
|
|
||||||
if (Input.IsKeyPressed(KeyCode.R))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Mat4 transform = GetTransform();
|
|
||||||
transform.Translation = new Vec3(0.0f);
|
|
||||||
SetTransform(transform);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -21,7 +21,6 @@ namespace Example
|
|||||||
|
|
||||||
public void OnUpdate(float ts)
|
public void OnUpdate(float ts)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
Rotation += ts;
|
Rotation += ts;
|
||||||
|
|
||||||
|
|
||||||
@ -35,10 +34,19 @@ namespace Example
|
|||||||
translation.Z += Velocity.Z * ts;
|
translation.Z += Velocity.Z * ts;
|
||||||
|
|
||||||
translation.Y -= SinkRate * ts;
|
translation.Y -= SinkRate * ts;
|
||||||
|
/*
|
||||||
|
if (Input.IsKeyPressed(KeyCode.Up))
|
||||||
|
translation.Y += speed;
|
||||||
|
else if (Input.IsKeyPressed(KeyCode.Down))
|
||||||
|
translation.Y -= speed;
|
||||||
|
if (Input.IsKeyPressed(KeyCode.Right))
|
||||||
|
translation.X += speed;
|
||||||
|
else if (Input.IsKeyPressed(KeyCode.Left))
|
||||||
|
translation.X -= speed;
|
||||||
|
*/
|
||||||
|
|
||||||
transform.Translation = translation;
|
transform.Translation = translation;
|
||||||
SetTransform(transform);
|
SetTransform(transform);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,6 @@ namespace Example
|
|||||||
|
|
||||||
void OnUpdate(float ts)
|
void OnUpdate(float ts)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
Mat4 transform = GetTransform();
|
Mat4 transform = GetTransform();
|
||||||
Vec3 translation = transform.Translation;
|
Vec3 translation = transform.Translation;
|
||||||
|
|
||||||
@ -22,7 +21,6 @@ namespace Example
|
|||||||
|
|
||||||
transform.Translation = translation;
|
transform.Translation = translation;
|
||||||
SetTransform(transform);
|
SetTransform(transform);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,17 +5,6 @@
|
|||||||
<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>
|
|
||||||
<Content Include="bin\Debug\net9.0\Prism-ScriptCore.deps.json" />
|
|
||||||
<Content Include="bin\Debug\net9.0\Prism-ScriptCore.dll" />
|
|
||||||
<Content Include="bin\Debug\net9.0\Prism-ScriptCore.pdb" />
|
|
||||||
<Content Include="bin\Release\net9.0\Prism-ScriptCore.deps.json" />
|
|
||||||
<Content Include="bin\Release\net9.0\Prism-ScriptCore.dll" />
|
|
||||||
<Content Include="bin\Release\net9.0\Prism-ScriptCore.pdb" />
|
|
||||||
<Content Include="Prism-ScriptCore.sln" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 18
|
|
||||||
VisualStudioVersion = 18.1.11312.151 d18.0
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prism-ScriptCore", "Prism-ScriptCore.csproj", "{B94EF710-0487-4388-97E3-B650761A849C}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prism-ScriptCore", "Prism-ScriptCore.csproj", "{B94EF710-0487-4388-97E3-B650761A849C}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
@ -16,10 +13,4 @@ Global
|
|||||||
{B94EF710-0487-4388-97E3-B650761A849C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B94EF710-0487-4388-97E3-B650761A849C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B94EF710-0487-4388-97E3-B650761A849C}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B94EF710-0487-4388-97E3-B650761A849C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {BA69725C-3CFE-4882-9EDF-2A8E92423E8F}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,54 +5,14 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
public class Entity
|
public class Entity
|
||||||
{
|
{
|
||||||
private Action<float>? m_CollisionBeginCallbacks;
|
|
||||||
private Action<float>? m_CollisionEndCallbacks;
|
|
||||||
private Action<float>? m_Collision2DBeginCallbacks;
|
|
||||||
private Action<float>? m_Collision2DEndCallbacks;
|
|
||||||
private Action<float>? m_TriggerBeginCallbacks;
|
|
||||||
private Action<float>? m_TriggerEndCallbacks;
|
|
||||||
|
|
||||||
public ulong ID { get; private set; }
|
public ulong ID { get; private set; }
|
||||||
|
|
||||||
~Entity()
|
~Entity()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 Translation
|
private List<Action<float>> m_Collision2DBeginCallbacks = new List<Action<float>>();
|
||||||
{
|
private List<Action<float>> m_Collision2DEndCallbacks = new List<Action<float>>();
|
||||||
get
|
|
||||||
{
|
|
||||||
return GetComponent<TransformComponent>().Translation;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
GetComponent<TransformComponent>().Translation = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 Rotation
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return GetComponent<TransformComponent>().Rotation;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
GetComponent<TransformComponent>().Rotation = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 Scale
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return GetComponent<TransformComponent>().Scale;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
GetComponent<TransformComponent>().Scale = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Entity() { ID = 0; }
|
protected Entity() { ID = 0; }
|
||||||
|
|
||||||
@ -91,86 +51,50 @@ namespace Prism
|
|||||||
return new Entity(entityID);
|
return new Entity(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity FindEntityByID(ulong entityID)
|
public Mat4 GetTransform()
|
||||||
{
|
{
|
||||||
// TODO: to verify it
|
Mat4 mat4Instance;
|
||||||
return new Entity(entityID);
|
GetTransform_Native(ID, out mat4Instance);
|
||||||
|
return mat4Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTransform(Mat4 transform)
|
||||||
|
{
|
||||||
|
SetTransform_Native(ID, ref transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCollision2DBeginCallback(Action<float> callback)
|
public void AddCollision2DBeginCallback(Action<float> callback)
|
||||||
{
|
{
|
||||||
m_Collision2DBeginCallbacks += callback;
|
m_Collision2DBeginCallbacks.Add(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCollision2DEndCallback(Action<float> callback)
|
public void AddCollision2DEndCallback(Action<float> callback)
|
||||||
{
|
{
|
||||||
m_Collision2DEndCallbacks += callback;
|
m_Collision2DEndCallbacks.Add(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCollisionBeginCallback(Action<float> callback)
|
|
||||||
{
|
|
||||||
m_CollisionBeginCallbacks += callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddCollisionEndCallback(Action<float> callback)
|
|
||||||
{
|
|
||||||
m_CollisionEndCallbacks += callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTriggerBeginCallback(Action<float> callback)
|
|
||||||
{
|
|
||||||
m_TriggerBeginCallbacks += callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTriggerEndCallback(Action<float> callback)
|
|
||||||
{
|
|
||||||
m_TriggerEndCallbacks += callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCollisionBegin(float data)
|
|
||||||
{
|
|
||||||
if (m_CollisionBeginCallbacks != null)
|
|
||||||
m_CollisionBeginCallbacks.Invoke(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCollisionEnd(float data)
|
|
||||||
{
|
|
||||||
if (m_CollisionEndCallbacks != null)
|
|
||||||
m_CollisionEndCallbacks.Invoke(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCollision2DBegin(float data)
|
private void OnCollision2DBegin(float data)
|
||||||
{
|
{
|
||||||
if(m_Collision2DBeginCallbacks != null)
|
foreach (var callback in m_Collision2DBeginCallbacks)
|
||||||
m_Collision2DBeginCallbacks.Invoke(data);
|
callback.Invoke(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCollision2DEnd(float data)
|
private void OnCollision2DEnd(float data)
|
||||||
{
|
{
|
||||||
if(m_Collision2DEndCallbacks != null)
|
foreach (var callback in m_Collision2DEndCallbacks)
|
||||||
m_Collision2DEndCallbacks.Invoke(data);
|
callback.Invoke(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTriggerBegin(float data)
|
|
||||||
{
|
|
||||||
if (m_TriggerBeginCallbacks != null)
|
|
||||||
m_TriggerBeginCallbacks.Invoke(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTriggerEnd(float data)
|
|
||||||
{
|
|
||||||
if (m_TriggerEndCallbacks != null)
|
|
||||||
m_TriggerEndCallbacks.Invoke(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern void CreateComponent_Native(ulong entityID, Type type);
|
private static extern void CreateComponent_Native(ulong entityID, Type type);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern bool HasComponent_Native(ulong entityID, Type type);
|
private static extern bool HasComponent_Native(ulong entityID, Type type);
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
private static extern void GetTransform_Native(ulong entityID, out Mat4 matrix);
|
||||||
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
|
private static extern void SetTransform_Native(ulong entityID, ref Mat4 matrix);
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern ulong FindEntityByTag_Native(string tag);
|
private static extern ulong FindEntityByTag_Native(string tag);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,61 +4,14 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
public class Input
|
public class Input
|
||||||
{
|
{
|
||||||
public enum CursorMode
|
|
||||||
{
|
|
||||||
Normal = 0,
|
|
||||||
Hidden = 1,
|
|
||||||
Locked = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum MouseButton
|
|
||||||
{
|
|
||||||
Button0 = 0,
|
|
||||||
Button1 = 1,
|
|
||||||
Button2 = 2,
|
|
||||||
Button3 = 3,
|
|
||||||
Button4 = 4,
|
|
||||||
Button5 = 5,
|
|
||||||
Left = Button0,
|
|
||||||
Right = Button1,
|
|
||||||
Middle = Button2
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static bool IsKeyPressed(KeyCode keycode)
|
public static bool IsKeyPressed(KeyCode keycode)
|
||||||
{
|
{
|
||||||
return IsKeyPressed_Native(keycode);
|
return IsKeyPressed_Native(keycode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsMouseButtonPressed(MouseButton button)
|
|
||||||
{
|
|
||||||
return IsMouseButtonPressed_Native(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec2 GetMousePosition()
|
|
||||||
{
|
|
||||||
GetMousePosition_Native(out Vec2 position);
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetCursorMode(CursorMode mode) => SetCursorMode_Native(mode);
|
|
||||||
public static CursorMode GetCursorMode() => GetCursorMode_Native();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
private static extern bool IsKeyPressed_Native(KeyCode keycode);
|
private static extern bool IsKeyPressed_Native(KeyCode keycode);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
private static extern bool IsMouseButtonPressed_Native(MouseButton button);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
private static extern void GetMousePosition_Native(out Vec2 position);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
private static extern void SetCursorMode_Native(CursorMode mode);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
private static extern CursorMode GetCursorMode_Native();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
public static class Mathf
|
|
||||||
{
|
|
||||||
public const float DegreeToRadians = (float)Math.PI * 2.0f / 360.0f;
|
|
||||||
public const float RadiansToDegrees = 360.0f / ((float)Math.PI * 2.0f);
|
|
||||||
public static float Clamp(float value, float min, float max)
|
|
||||||
{
|
|
||||||
if (value < min) return min;
|
|
||||||
if (value > max) return max;
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct Transform
|
|
||||||
{
|
|
||||||
public Vec3 Position;
|
|
||||||
public Vec3 Rotation;
|
|
||||||
public Vec3 Scale;
|
|
||||||
|
|
||||||
public Vec3 Up;
|
|
||||||
public Vec3 Right;
|
|
||||||
public Vec3 Forward;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -8,8 +8,6 @@ namespace Prism
|
|||||||
public float X;
|
public float X;
|
||||||
public float Y;
|
public float Y;
|
||||||
|
|
||||||
|
|
||||||
public static Vec2 Zero = new Vec2(0.0f, 0.0f);
|
|
||||||
public Vec2(float scalar)
|
public Vec2(float scalar)
|
||||||
{
|
{
|
||||||
X = Y = scalar;
|
X = Y = scalar;
|
||||||
@ -27,68 +25,20 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Clamp(Vec2 min, Vec2 max) {
|
public void Clamp(Vec2 min, Vec2 max) {
|
||||||
X = Mathf.Clamp(X, min.X, max.X);
|
if (X < min.X)
|
||||||
Y = Mathf.Clamp(Y, min.Y, max.Y);
|
X = min.X;
|
||||||
|
if (X > max.X)
|
||||||
|
X = max.X;
|
||||||
|
|
||||||
|
if (Y < min.Y)
|
||||||
|
Y = min.Y;
|
||||||
|
if (Y > max.Y)
|
||||||
|
Y = max.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float LengthSquared()
|
|
||||||
{
|
|
||||||
return X * X + Y * Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Length()
|
|
||||||
{
|
|
||||||
return (float)Math.Sqrt(X * X + Y * Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec2 SafeNormalized()
|
|
||||||
{
|
|
||||||
float length = Length();
|
|
||||||
if (length > float.Epsilon)
|
|
||||||
{
|
|
||||||
return new Vec2(X / length, Y / length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Vec2 Normalized()
|
|
||||||
{
|
|
||||||
float length = Length();
|
|
||||||
return new Vec2(X / length, Y / length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SafeNormalize()
|
|
||||||
{
|
|
||||||
float length = Length();
|
|
||||||
if (length > float.Epsilon)
|
|
||||||
{
|
|
||||||
X = X / length;
|
|
||||||
Y = Y / length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Normalize()
|
|
||||||
{
|
|
||||||
float length = Length();
|
|
||||||
X = X / length;
|
|
||||||
Y = Y / length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec2 operator -(Vec2 l, Vec2 r)
|
|
||||||
{
|
|
||||||
return new Vec2(l.X - r.X, l.Y - r.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec2 operator -(Vec2 vector)
|
public static Vec2 operator -(Vec2 vector)
|
||||||
{
|
{
|
||||||
return new Vec2(-vector.X, -vector.Y);
|
return new Vec2(-vector.X, -vector.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"({X}, {Y})";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,12 +5,6 @@ namespace Prism
|
|||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct Vec3
|
public struct Vec3
|
||||||
{
|
{
|
||||||
public static Vec3 Zero = new Vec3(0.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
public static Vec3 Forward = new Vec3(0.0f, 0.0f, -1.0f);
|
|
||||||
public static Vec3 Right = new Vec3(1.0f, 0.0f, 0.0f);
|
|
||||||
public static Vec3 Up = new Vec3(0.0f, 1.0f, 0.0f);
|
|
||||||
|
|
||||||
public float X;
|
public float X;
|
||||||
public float Y;
|
public float Y;
|
||||||
public float Z;
|
public float Z;
|
||||||
@ -20,24 +14,11 @@ namespace Prism
|
|||||||
X = Y = Z = scalar;
|
X = Y = Z = scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3(Vec2 vec2) {
|
public Vec3(Vec2 vec) {
|
||||||
X = vec2.X;
|
X = vec.X;
|
||||||
Y = vec2.Y;
|
Y = vec.Y;
|
||||||
Z = 0.0f;
|
Z = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3(Vec2 vec2, float z) {
|
|
||||||
X = vec2.X;
|
|
||||||
Y = vec2.Y;
|
|
||||||
Z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3(float x, Vec2 vec2)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = vec2.X;
|
|
||||||
Z = vec2.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3(float x, float y, float z)
|
public Vec3(float x, float y, float z)
|
||||||
{
|
{
|
||||||
@ -45,65 +26,12 @@ namespace Prism
|
|||||||
Y = y;
|
Y = y;
|
||||||
Z = z;
|
Z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Vec3(Vec4 vec) {
|
public Vec3(Vec4 vec) {
|
||||||
X = vec.X;
|
X = vec.X;
|
||||||
Y = vec.Y;
|
Y = vec.Y;
|
||||||
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)
|
|
||||||
{
|
|
||||||
X = Mathf.Clamp(X, min.X, max.X);
|
|
||||||
Y = Mathf.Clamp(Y, min.Y, max.Y);
|
|
||||||
Z = Mathf.Clamp(Z, min.Z, max.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public float LengthSquared()
|
|
||||||
{
|
|
||||||
return X * X + Y * Y + Z * Z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Length()
|
|
||||||
{
|
|
||||||
return (float)Math.Sqrt(X * X + Y * Y + Z * Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 Normalized()
|
|
||||||
{
|
|
||||||
float length = Length();
|
|
||||||
if (length > float.Epsilon)
|
|
||||||
{
|
|
||||||
return new Vec3(X / length, Y / length, Z / length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Normalize()
|
|
||||||
{
|
|
||||||
float length = Length();
|
|
||||||
if (length > float.Epsilon)
|
|
||||||
{
|
|
||||||
X = X / length;
|
|
||||||
Y = Y / length;
|
|
||||||
Z = Z / length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Vec2 XY {
|
public Vec2 XY {
|
||||||
get { return new Vec2(X, Y); }
|
get { return new Vec2(X, Y); }
|
||||||
@ -121,61 +49,5 @@ namespace Prism
|
|||||||
set { Y = value.X; Z = value.Y; }
|
set { Y = value.X; Z = value.Y; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static Vec3 operator *(Vec3 left, float scalar)
|
|
||||||
{
|
|
||||||
return new Vec3(left.X * scalar, left.Y * scalar, left.Z * scalar);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 operator *(float scalar, Vec3 right)
|
|
||||||
{
|
|
||||||
return new Vec3(scalar * right.X, scalar * right.Y, scalar * right.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 operator +(Vec3 left, Vec3 right)
|
|
||||||
{
|
|
||||||
return new Vec3(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 operator +(Vec3 left, float right)
|
|
||||||
{
|
|
||||||
return new Vec3(left.X + right, left.Y + right, left.Z + right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 operator -(Vec3 left, Vec3 right)
|
|
||||||
{
|
|
||||||
return new Vec3(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 operator /(Vec3 left, Vec3 right)
|
|
||||||
{
|
|
||||||
return new Vec3(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 operator /(Vec3 left, float scalar)
|
|
||||||
{
|
|
||||||
return new Vec3(left.X / scalar, left.Y / scalar, left.Z / scalar);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 operator-(Vec3 vector)
|
|
||||||
{
|
|
||||||
return new Vec3(-vector.X, -vector.Y, -vector.Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 Cos(Vec3 vector)
|
|
||||||
{
|
|
||||||
return new Vec3((float)Math.Cos(vector.X), (float)Math.Cos(vector.Y), (float)Math.Cos(vector.Z));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vec3 Sin(Vec3 vector)
|
|
||||||
{
|
|
||||||
return new Vec3((float)Math.Sin(vector.X), (float)Math.Sin(vector.Y), (float)Math.Sin(vector.Z));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"({X}, {Y}, {Z})";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,13 +2,13 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
public struct Vec4
|
public struct Vec4
|
||||||
{
|
{
|
||||||
public float X;
|
[FieldOffset(0)] public float X;
|
||||||
public float Y;
|
[FieldOffset(4)] public float Y;
|
||||||
public float Z;
|
[FieldOffset(8)] public float Z;
|
||||||
public float W;
|
[FieldOffset(12)] public float W;
|
||||||
|
|
||||||
public Vec4(float scalar)
|
public Vec4(float scalar)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,100 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
public class Collider
|
|
||||||
{
|
|
||||||
public ulong EntityID { get; protected set; }
|
|
||||||
public bool IsTrigger { get; protected set; }
|
|
||||||
|
|
||||||
private Entity entity;
|
|
||||||
private RigidBodyComponent _rigidBodyComponent;
|
|
||||||
|
|
||||||
public Entity Entity
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (entity == null)
|
|
||||||
entity = new Entity(EntityID);
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RigidBodyComponent RigidBody
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_rigidBodyComponent == null)
|
|
||||||
_rigidBodyComponent = Entity.GetComponent<RigidBodyComponent>();
|
|
||||||
|
|
||||||
return _rigidBodyComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
string type = "Collider";
|
|
||||||
|
|
||||||
if (this is BoxCollider) type = "BoxCollider";
|
|
||||||
else if (this is SphereCollider) type = "SphereCollider";
|
|
||||||
else if (this is CapsuleCollider) type = "CapsuleCollider";
|
|
||||||
else if (this is MeshCollider) type = "MeshCollider";
|
|
||||||
|
|
||||||
return "Collider(" + type + ", " + EntityID + ", " + IsTrigger + ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BoxCollider : Collider
|
|
||||||
{
|
|
||||||
public Vec3 Size { get; protected set; }
|
|
||||||
public Vec3 Offset { get; protected set; }
|
|
||||||
|
|
||||||
internal BoxCollider(ulong entityID, bool isTrigger, Vec3 size, Vec3 offset)
|
|
||||||
{
|
|
||||||
EntityID = entityID;
|
|
||||||
Size = size;
|
|
||||||
Offset = offset;
|
|
||||||
IsTrigger = isTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SphereCollider : Collider
|
|
||||||
{
|
|
||||||
public float Radius { get; protected set; }
|
|
||||||
|
|
||||||
internal SphereCollider(ulong entityID, bool isTrigger, float radius)
|
|
||||||
{
|
|
||||||
EntityID = entityID;
|
|
||||||
Radius = radius;
|
|
||||||
IsTrigger = isTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CapsuleCollider : Collider
|
|
||||||
{
|
|
||||||
public float Radius { get; protected set; }
|
|
||||||
public float Height { get; protected set; }
|
|
||||||
|
|
||||||
internal CapsuleCollider(ulong entityID, bool isTrigger, float radius, float height)
|
|
||||||
{
|
|
||||||
EntityID = entityID;
|
|
||||||
Radius = radius;
|
|
||||||
Height = height;
|
|
||||||
IsTrigger = isTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MeshCollider : Collider
|
|
||||||
{
|
|
||||||
public Mesh Mesh { get; protected set; }
|
|
||||||
|
|
||||||
internal MeshCollider(ulong entityID, bool isTrigger, IntPtr filepath)
|
|
||||||
{
|
|
||||||
EntityID = entityID;
|
|
||||||
Mesh = new Mesh(filepath);
|
|
||||||
IsTrigger = isTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct RaycastHit
|
|
||||||
{
|
|
||||||
public ulong EntityID { get; private set; }
|
|
||||||
public Vec3 Position { get; private set; }
|
|
||||||
public Vec3 Normal { get; private set; }
|
|
||||||
public float Distance { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Physics
|
|
||||||
{
|
|
||||||
public static bool Raycast(Vec3 origin, Vec3 direction, float maxDistance, out RaycastHit hit)
|
|
||||||
{
|
|
||||||
return Raycast_Native(ref origin, ref direction, maxDistance, out hit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Collider[] OverlapBox(Vec3 origin, Vec3 halfSize)
|
|
||||||
{
|
|
||||||
return OverlapBox_Native(ref origin, ref halfSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Collider[] OverlapCapsule(Vec3 origin, float radius, float halfHeight)
|
|
||||||
{
|
|
||||||
return OverlapCapsule_Native(ref origin, radius, halfHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Collider[] OverlapSphere(Vec3 origin, float radius)
|
|
||||||
{
|
|
||||||
return OverlapSphere_Native(ref origin, radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int OverlapBoxNonAlloc(Vec3 origin, Vec3 halfSize, Collider[] colliders)
|
|
||||||
{
|
|
||||||
return OverlapBoxNonAlloc_Native(ref origin, ref halfSize, colliders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int OverlapCapsuleNonAlloc(Vec3 origin, float radius, float halfHeight, Collider[] colliders)
|
|
||||||
{
|
|
||||||
return OverlapCapsuleNonAlloc_Native(ref origin, radius, halfHeight, colliders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int OverlapSphereNonAlloc(Vec3 origin, float radius, Collider[] colliders)
|
|
||||||
{
|
|
||||||
return OverlapSphereNonAlloc_Native(ref origin, radius, colliders);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern bool Raycast_Native(ref Vec3 origin, ref Vec3 direction, float maxDistance, out RaycastHit hit);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern Collider[] OverlapBox_Native(ref Vec3 origin, ref Vec3 halfSize);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern Collider[] OverlapCapsule_Native(ref Vec3 origin, float radius, float halfHeight);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern Collider[] OverlapSphere_Native(ref Vec3 origin, float radius);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern int OverlapBoxNonAlloc_Native(ref Vec3 origin, ref Vec3 halfSize, Collider[] colliders);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern int OverlapCapsuleNonAlloc_Native(ref Vec3 origin, float radius, float halfHeight, Collider[] colliders);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern int OverlapSphereNonAlloc_Native(ref Vec3 origin, float radius, Collider[] colliders);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -32,12 +31,13 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class TransformComponent : Component
|
public class TransformComponent : Component
|
||||||
{
|
{
|
||||||
public Transform Transform
|
public Mat4 Transform
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
GetTransform_Native(Entity.ID, out Transform result);
|
Mat4 result;
|
||||||
|
GetTransform_Native(Entity.ID, out result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
@ -46,68 +46,12 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 Translation
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
{
|
public static extern void GetTransform_Native(ulong entityID, out Mat4 result);
|
||||||
get
|
|
||||||
{
|
|
||||||
GetTranslation_Native(Entity.ID, out Vec3 result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SetTranslation_Native(Entity.ID, ref value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 Rotation
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
GetRotation_Native(Entity.ID, out Vec3 result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SetRotation_Native(Entity.ID, ref value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 Scale
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
GetScale_Native(Entity.ID, out Vec3 result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SetScale_Native(Entity.ID, ref value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal static extern void GetTransform_Native(ulong entityID, out Transform inTransform);
|
public static extern void SetTransform_Native(ulong entityID, ref Mat4 result);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void SetTransform_Native(ulong entityID, ref Transform outTransform);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void GetTranslation_Native(ulong entityID, out Vec3 outTranslation);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void SetTranslation_Native(ulong entityID, ref Vec3 inTranslation);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void GetRotation_Native(ulong entityID, out Vec3 outRotation);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void SetRotation_Native(ulong entityID, ref Vec3 inRotation);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void GetScale_Native(ulong entityID, out Vec3 outScale);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void SetScale_Native(ulong entityID, ref Vec3 inScale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MeshComponent : Component
|
public class MeshComponent : Component
|
||||||
@ -179,121 +123,4 @@ namespace Prism
|
|||||||
public class BoxCollider2DComponent : Component
|
public class BoxCollider2DComponent : Component
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BoxColliderComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SphereColliderComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RigidBodyComponent : Component
|
|
||||||
{
|
|
||||||
public enum Type
|
|
||||||
{
|
|
||||||
Static,
|
|
||||||
Dynamic
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ForceMode
|
|
||||||
{
|
|
||||||
Force = 0,
|
|
||||||
Impulse,
|
|
||||||
VelocityChange,
|
|
||||||
Acceleration
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type BodyType
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return GetBodyType_Native(Entity.ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Mass
|
|
||||||
{
|
|
||||||
get { return GetMass_Native(Entity.ID); }
|
|
||||||
set { SetMass_Native(Entity.ID, value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint Layer
|
|
||||||
{
|
|
||||||
get { return GetLayer_Native(Entity.ID); }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void AddForce(Vec3 force, ForceMode forceMode = ForceMode.Force)
|
|
||||||
{
|
|
||||||
AddForce_Native(Entity.ID, ref force, forceMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddTorque(Vec3 torque, ForceMode forceMode = ForceMode.Force)
|
|
||||||
{
|
|
||||||
AddTorque_Native(Entity.ID, ref torque, forceMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 GetLinearVelocity()
|
|
||||||
{
|
|
||||||
GetLinearVelocity_Native(Entity.ID, out Vec3 velocity);
|
|
||||||
return velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetLinearVelocity(Vec3 velocity)
|
|
||||||
{
|
|
||||||
SetLinearVelocity_Native(Entity.ID, ref velocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 GetAngularVelocity()
|
|
||||||
{
|
|
||||||
GetAngularVelocity_Native(Entity.ID, out Vec3 velocity);
|
|
||||||
return velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetAngularVelocity(Vec3 velocity)
|
|
||||||
{
|
|
||||||
SetAngularVelocity_Native(Entity.ID, ref velocity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Rotate(Vec3 rotation)
|
|
||||||
{
|
|
||||||
Rotate_Native(Entity.ID, ref rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Add SetMaxLinearVelocity() as well
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void AddForce_Native(ulong entityID, ref Vec3 force, ForceMode forceMode);
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void AddTorque_Native(ulong entityID, ref Vec3 torque, ForceMode forceMode);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void GetLinearVelocity_Native(ulong entityID, out Vec3 velocity);
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void SetLinearVelocity_Native(ulong entityID, ref Vec3 velocity);
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
|
|
||||||
internal static extern void GetAngularVelocity_Native(ulong entityID, out Vec3 velocity);
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void SetAngularVelocity_Native(ulong entityID, ref Vec3 velocity);
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern void Rotate_Native(ulong entityID, ref Vec3 rotation);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern uint GetLayer_Native(ulong entityID);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern float GetMass_Native(ulong entityID);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern float SetMass_Native(ulong entityID, float mass);
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
|
||||||
internal static extern Type GetBodyType_Native(ulong entityID);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ add_subdirectory(vendor/mono EXCLUDE_FROM_ALL)
|
|||||||
add_subdirectory(vendor/FastNoise EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/FastNoise EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/yaml-cpp EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/yaml-cpp EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/Box2D EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/Box2D EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/efsw EXCLUDE_FROM_ALL)
|
|
||||||
|
|
||||||
|
|
||||||
# ------------- imgui -------------
|
# ------------- imgui -------------
|
||||||
@ -47,42 +46,6 @@ list(APPEND SRC_SOURCE ${IMGUIZMO_SOURCE})
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ----------- ImViewGuizmo -------------
|
|
||||||
set(IMVIEWGUIZMO_DIR vendor/ImViewGuizmo)
|
|
||||||
|
|
||||||
|
|
||||||
# ------------- NVIDIA PhysX -------------
|
|
||||||
# PhysX/physx/buildtools/presets/*.xml
|
|
||||||
# PX_GENERATE_STATIC_LIBRARIES=True
|
|
||||||
# NV_USE_STATIC_WINCRT=False
|
|
||||||
|
|
||||||
set(PHYSX_BUILD_TYPE "checked" CACHE STRING "The build type of PhysX")
|
|
||||||
set_property(CACHE PHYSX_BUILD_TYPE PROPERTY STRINGS debug checked profile release)
|
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
|
||||||
if(PHYSX_BUILD_TYPE STREQUAL "debug" OR PHYSX_BUILD_TYPE STREQUAL "checked")
|
|
||||||
set(CMAKE_BUILD_TYPE "Debug")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
|
||||||
set(PHYSX_BUILD_TYPE "release")
|
|
||||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
set(PHYSX_BUILD_TYPE "debug")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
include_directories(vendor/PhysX/physx/include)
|
|
||||||
set(PHYSX_LIB_DIR "vendor/PhysX/physx/bin/win.x86_64.vc143.md/${PHYSX_BUILD_TYPE}") # This is the path where PhysX libraries are installed
|
|
||||||
link_directories(${PHYSX_LIB_DIR})
|
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
message("Building snippet in debug with PhysX ${PHYSX_BUILD_TYPE} configuration")
|
|
||||||
add_compile_definitions(_DEBUG)
|
|
||||||
else()
|
|
||||||
message("Building snippet in release configuration with PhysX ${PHYSX_BUILD_TYPE} configuration")
|
|
||||||
add_compile_definitions(NDEBUG)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# ------------- link libraries -------------
|
# ------------- link libraries -------------
|
||||||
set(LINK_LIBRARIES_PRIVATE
|
set(LINK_LIBRARIES_PRIVATE
|
||||||
glfw
|
glfw
|
||||||
@ -92,14 +55,6 @@ set(LINK_LIBRARIES_PRIVATE
|
|||||||
tinyFileDialogs
|
tinyFileDialogs
|
||||||
FastNoise
|
FastNoise
|
||||||
yaml-cpp
|
yaml-cpp
|
||||||
efsw
|
|
||||||
|
|
||||||
PhysXExtensions_static_64
|
|
||||||
PhysX_static_64
|
|
||||||
PhysXPvdSDK_static_64
|
|
||||||
PhysXCommon_static_64
|
|
||||||
PhysXFoundation_static_64
|
|
||||||
PhysXCooking_static_64
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LINK_LIBRARIES_PUBLIC
|
set(LINK_LIBRARIES_PUBLIC
|
||||||
@ -124,17 +79,15 @@ set(TARGET_INCLUDE_DIR
|
|||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
||||||
${IMGUI_DIR}
|
${IMGUI_DIR}
|
||||||
${IMGUIZMO_DIR}
|
${IMGUIZMO_DIR}
|
||||||
${IMVIEWGUIZMO_DIR}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# ------------- debug Defines -------------
|
# ------------- debug Defines -------------
|
||||||
set(DEBUG_DEFINITIONS
|
set(DEBUG_DEFINITIONS
|
||||||
$<$<CONFIG:Debug>:PM_ENABLE_ASSERTS>
|
$<$<CONFIG:Debug>:PM_ENABLE_ASSERTS>
|
||||||
$<$<CONFIG:RelWithDebInfo>:PM_ENABLE_ASSERTS>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# static library
|
# static library
|
||||||
set(STATIC_LIBRARY ${PROJECT_NAME}-static)
|
set(STATIC_LIBRARY ${PROJECT_NAME}-static)
|
||||||
|
|
||||||
add_library(${STATIC_LIBRARY} STATIC ${SRC_SOURCE})
|
add_library(${STATIC_LIBRARY} STATIC ${SRC_SOURCE})
|
||||||
@ -148,11 +101,6 @@ target_compile_definitions(${STATIC_LIBRARY} PRIVATE
|
|||||||
target_include_directories(${STATIC_LIBRARY} PUBLIC
|
target_include_directories(${STATIC_LIBRARY} PUBLIC
|
||||||
${TARGET_INCLUDE_DIR}
|
${TARGET_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_directories(${STATIC_LIBRARY} INTERFACE
|
|
||||||
${PHYSX_LIB_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(${STATIC_LIBRARY}
|
target_link_libraries(${STATIC_LIBRARY}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${LINK_LIBRARIES_PRIVATE}
|
${LINK_LIBRARIES_PRIVATE}
|
||||||
@ -197,45 +145,7 @@ 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)
|
|
||||||
|
|||||||
@ -1,79 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/3/9.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "AnimationClip.h"
|
|
||||||
|
|
||||||
#include "assimp/scene.h"
|
|
||||||
|
|
||||||
struct aiAnimation;
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
AnimationClip::AnimationClip(const aiScene* scene)
|
|
||||||
{
|
|
||||||
const aiAnimation* anim = scene->mAnimations[0]; // 先只处理第一个动画
|
|
||||||
m_Duration = (float)anim->mDuration;
|
|
||||||
m_TicksPerSecond = (float)(anim->mTicksPerSecond != 0 ? anim->mTicksPerSecond : 25.0);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < anim->mNumChannels; i++)
|
|
||||||
{
|
|
||||||
aiNodeAnim* nodeAnim = anim->mChannels[i];
|
|
||||||
BoneChannel channel;
|
|
||||||
channel.BoneName = nodeAnim->mNodeName.C_Str();
|
|
||||||
|
|
||||||
// 位置关键帧
|
|
||||||
for (uint32_t j = 0; j < nodeAnim->mNumPositionKeys; j++)
|
|
||||||
{
|
|
||||||
const auto& key = nodeAnim->mPositionKeys[j];
|
|
||||||
channel.Positions.emplace_back((float)key.mTime,
|
|
||||||
glm::vec3(key.mValue.x, key.mValue.y, key.mValue.z));
|
|
||||||
}
|
|
||||||
// 旋转关键帧
|
|
||||||
for (uint32_t j = 0; j < nodeAnim->mNumRotationKeys; j++)
|
|
||||||
{
|
|
||||||
const auto& key = nodeAnim->mRotationKeys[j];
|
|
||||||
channel.Rotations.emplace_back((float)key.mTime,
|
|
||||||
glm::quat(key.mValue.w, key.mValue.x, key.mValue.y, key.mValue.z));
|
|
||||||
}
|
|
||||||
// 缩放关键帧
|
|
||||||
for (uint32_t j = 0; j < nodeAnim->mNumScalingKeys; j++)
|
|
||||||
{
|
|
||||||
const auto& key = nodeAnim->mScalingKeys[j];
|
|
||||||
channel.Scalings.emplace_back((float)key.mTime,
|
|
||||||
glm::vec3(key.mValue.x, key.mValue.y, key.mValue.z));
|
|
||||||
}
|
|
||||||
m_BoneChannels.push_back(channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::mat4 AnimationClip::SampleAtTime(const float timeTicks, const std::string& boneName, const glm::mat4& defaultTransform) const
|
|
||||||
{
|
|
||||||
for (const auto& channel : m_BoneChannels) {
|
|
||||||
if (channel.BoneName == boneName) {
|
|
||||||
const glm::vec3 pos = SampleChannel(channel.Positions, timeTicks, glm::vec3(0.0f));
|
|
||||||
const glm::quat rot = SampleChannel(channel.Rotations, timeTicks, glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
|
|
||||||
const glm::vec3 scl = SampleChannel(channel.Scalings, timeTicks, glm::vec3(1.0f));
|
|
||||||
return glm::translate(glm::mat4(1.0f), pos) * glm::toMat4(rot) * glm::scale(glm::mat4(1.0f), scl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaultTransform;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T AnimationClip::SampleChannel(const std::vector<KeyFrame<T>>& keys, float time, const T& defaultValue) const
|
|
||||||
{
|
|
||||||
if (keys.empty()) return defaultValue;
|
|
||||||
if (time <= keys.front().Time) return keys.front().Value;
|
|
||||||
if (time >= keys.back().Time) return keys.back().Value;
|
|
||||||
|
|
||||||
// 找到当前时间所在的关键帧区间
|
|
||||||
for (size_t i = 0; i < keys.size() - 1; ++i) {
|
|
||||||
if (time >= keys[i].Time && time <= keys[i+1].Time) {
|
|
||||||
float t = (time - keys[i].Time) / (keys[i+1].Time - keys[i].Time);
|
|
||||||
return Interpolate(keys[i].Value, keys[i+1].Value, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/3/9.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef PRISM_ANIMATIONCLIP_H
|
|
||||||
#define PRISM_ANIMATIONCLIP_H
|
|
||||||
#include "Prism/Asset/Asset.h"
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#define GLM_ENABLE_EXPERIMENTAL
|
|
||||||
#include <glm/gtx/quaternion.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
struct aiScene;
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
template<typename T>
|
|
||||||
struct KeyFrame
|
|
||||||
{
|
|
||||||
float Time = 0.0f;
|
|
||||||
T Value;
|
|
||||||
|
|
||||||
KeyFrame() = default;
|
|
||||||
KeyFrame(const float t, const T& v) : Time(t), Value(v) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BoneChannel {
|
|
||||||
std::string BoneName;
|
|
||||||
std::vector<KeyFrame<glm::vec3>> Positions;
|
|
||||||
std::vector<KeyFrame<glm::quat>> Rotations;
|
|
||||||
std::vector<KeyFrame<glm::vec3>> Scalings;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class PRISM_API AnimationClip : public Asset
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AnimationClip(const aiScene* scene);
|
|
||||||
glm::mat4 SampleAtTime(float timeTicks, const std::string& boneName, const glm::mat4& defaultTransform) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// 辅助采样模板函数
|
|
||||||
template<typename T>
|
|
||||||
T SampleChannel(const std::vector<KeyFrame<T>>& keys, float time, const T& defaultValue) const;
|
|
||||||
|
|
||||||
glm::vec3 Interpolate(const glm::vec3& a, const glm::vec3& b, const float t) const {
|
|
||||||
return glm::mix(a, b, t);
|
|
||||||
}
|
|
||||||
glm::quat Interpolate(const glm::quat& a, const glm::quat& b, const float t) const {
|
|
||||||
return glm::slerp(a, b, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
float m_Duration = 0.0f;
|
|
||||||
float m_TicksPerSecond;
|
|
||||||
std::vector<BoneChannel> m_BoneChannels;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //PRISM_ANIMATIONCLIP_H
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/3/9.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "AnimatorController.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
AnimationController::~AnimationController()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationController::Update(const float deltaTime)
|
|
||||||
{
|
|
||||||
if (m_State != PLAY || !m_currentClip || !m_skeleton)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const float rawTime = m_AnimationCurrentTime + deltaTime * m_currentClip->m_TicksPerSecond * m_TimeMultiplier;
|
|
||||||
const float duration = m_currentClip->m_Duration;
|
|
||||||
|
|
||||||
if (!m_Loop && rawTime >= duration)
|
|
||||||
{
|
|
||||||
m_AnimationCurrentTime = 0.0f;
|
|
||||||
m_State = STOP;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_AnimationCurrentTime = fmod(rawTime, duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
ComputeBoneTransforms(m_AnimationCurrentTime);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationController::SetSkeleton(const Ref<Skeleton>& skeleton)
|
|
||||||
{
|
|
||||||
m_skeleton = skeleton;
|
|
||||||
if (m_skeleton)
|
|
||||||
{
|
|
||||||
ComputeBindPoseTransforms();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationController::ComputeBoneTransforms(float time)
|
|
||||||
{
|
|
||||||
const auto boneCount = (uint32_t)m_skeleton->m_Bones.size();
|
|
||||||
m_FinalBoneTransforms.resize(boneCount);
|
|
||||||
|
|
||||||
std::vector<glm::mat4> localTransforms(boneCount, glm::mat4(1.0f));
|
|
||||||
for (uint32_t i = 0; i < boneCount; i++)
|
|
||||||
{
|
|
||||||
const BoneInfo& bone = m_skeleton->m_Bones[i];
|
|
||||||
if (m_currentClip)
|
|
||||||
{
|
|
||||||
localTransforms[i] = m_currentClip->SampleAtTime(time, bone.Name, bone.LocalBindPose);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
localTransforms[i] = bone.LocalBindPose;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 递归计算全局变换(从根骨骼开始)
|
|
||||||
std::function<void(uint32_t, const glm::mat4&)> computeGlobal = [&](const uint32_t boneIdx, const glm::mat4& parentGlobal)
|
|
||||||
{
|
|
||||||
const glm::mat4 global = parentGlobal * localTransforms[boneIdx];
|
|
||||||
glm::mat4 final = global * m_skeleton->m_Bones[boneIdx].InverseTransform;
|
|
||||||
final = m_GlobalInverseTransform * final;
|
|
||||||
m_FinalBoneTransforms[boneIdx] = final;
|
|
||||||
|
|
||||||
for (uint32_t childIdx = 0; childIdx < boneCount; childIdx++)
|
|
||||||
{
|
|
||||||
if (m_skeleton->m_Bones[childIdx].ParentIndex == (int)boneIdx)
|
|
||||||
{
|
|
||||||
computeGlobal(childIdx, global);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < boneCount; i++)
|
|
||||||
{
|
|
||||||
if (m_skeleton->m_Bones[i].ParentIndex == -1)
|
|
||||||
{
|
|
||||||
computeGlobal(i, glm::mat4(1.0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationController::ComputeBindPoseTransforms()
|
|
||||||
{
|
|
||||||
if (!m_skeleton) return;
|
|
||||||
|
|
||||||
uint32_t boneCount = (uint32_t)m_skeleton->m_Bones.size();
|
|
||||||
m_FinalBoneTransforms.resize(boneCount);
|
|
||||||
|
|
||||||
// 1. 收集每个骨骼的绑定姿势局部变换
|
|
||||||
std::vector<glm::mat4> localTransforms(boneCount);
|
|
||||||
for (uint32_t i = 0; i < boneCount; i++)
|
|
||||||
localTransforms[i] = m_skeleton->m_Bones[i].LocalBindPose;
|
|
||||||
|
|
||||||
// 2. 递归计算全局变换,并应用逆绑定矩阵和全局逆矩阵
|
|
||||||
std::function<void(uint32_t, const glm::mat4&)> computeGlobal =
|
|
||||||
[&](uint32_t idx, const glm::mat4& parentGlobal)
|
|
||||||
{
|
|
||||||
glm::mat4 global = parentGlobal * localTransforms[idx];
|
|
||||||
glm::mat4 final = m_GlobalInverseTransform * global * m_skeleton->m_Bones[idx].InverseTransform;
|
|
||||||
m_FinalBoneTransforms[idx] = final;
|
|
||||||
|
|
||||||
// 处理子骨骼
|
|
||||||
for (uint32_t child = 0; child < boneCount; child++)
|
|
||||||
{
|
|
||||||
if (m_skeleton->m_Bones[child].ParentIndex == (int)idx)
|
|
||||||
computeGlobal(child, global);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 从所有根骨骼开始递归
|
|
||||||
for (uint32_t i = 0; i < boneCount; i++)
|
|
||||||
{
|
|
||||||
if (m_skeleton->m_Bones[i].ParentIndex == -1)
|
|
||||||
computeGlobal(i, glm::mat4(1.0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/3/9.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef PRISM_ANIMATORCONTROLLER_H
|
|
||||||
#define PRISM_ANIMATORCONTROLLER_H
|
|
||||||
#include "AnimationClip.h"
|
|
||||||
#include "Skeleton.h"
|
|
||||||
#include "Prism/Asset/Asset.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
class PRISM_API AnimationController : public Asset
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum AnimationState : uint8_t
|
|
||||||
{
|
|
||||||
STOP = 0,
|
|
||||||
PLAY,
|
|
||||||
PAUSE
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
~AnimationController();
|
|
||||||
|
|
||||||
void Update(const float deltaTime);
|
|
||||||
|
|
||||||
const std::vector<glm::mat4>& GetFinalBoneTransforms() const { return m_FinalBoneTransforms; }
|
|
||||||
|
|
||||||
|
|
||||||
void SetSkeleton(const Ref<Skeleton>& skeleton);
|
|
||||||
void SetAnimationClip(const Ref<AnimationClip>& clip) { m_currentClip = clip; }
|
|
||||||
void SetGlobalInverseTransform(const glm::mat4& inv) { m_GlobalInverseTransform = inv; }
|
|
||||||
|
|
||||||
void Play() { m_State = PLAY; }
|
|
||||||
void Pause() { m_State = PAUSE; }
|
|
||||||
void Stop() { if (m_State == STOP) return; m_State = STOP; m_AnimationCurrentTime = 0.0f; ComputeBindPoseTransforms(); }
|
|
||||||
AnimationState GetAnimationState() const { return m_State; }
|
|
||||||
|
|
||||||
float& GetCurrentTime() { return m_AnimationCurrentTime; }
|
|
||||||
float& GetMultiplierTime() { return m_TimeMultiplier; }
|
|
||||||
bool& GetLoop() { return m_Loop; }
|
|
||||||
private:
|
|
||||||
void ComputeBoneTransforms(float time);
|
|
||||||
void ComputeBindPoseTransforms();
|
|
||||||
|
|
||||||
Ref<Skeleton> m_skeleton = nullptr;
|
|
||||||
Ref<AnimationClip> m_currentClip = nullptr;
|
|
||||||
AnimationState m_State = STOP;
|
|
||||||
|
|
||||||
float m_AnimationCurrentTime = 0.0f;
|
|
||||||
float m_TimeMultiplier = 1.0f;
|
|
||||||
bool m_Loop = false;
|
|
||||||
std::vector<glm::mat4> m_FinalBoneTransforms;
|
|
||||||
|
|
||||||
glm::mat4 m_GlobalInverseTransform = glm::mat4(1.0f);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //PRISM_ANIMATORCONTROLLER_H
|
|
||||||
@ -1,68 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/3/9.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Skeleton.h"
|
|
||||||
|
|
||||||
#include "assimp/scene.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
|
|
||||||
// TODO: this maybe move Utils
|
|
||||||
extern glm::mat4 Mat4FromAssimpMat4(const aiMatrix4x4& matrix);
|
|
||||||
|
|
||||||
|
|
||||||
Skeleton::Skeleton(const aiScene* scene)
|
|
||||||
{
|
|
||||||
// 收集所有骨骼(通过所有 Mesh 中的 aiBone)
|
|
||||||
for (uint32_t am = 0; am < scene->mNumMeshes; am++)
|
|
||||||
{
|
|
||||||
const aiMesh* aMesh = scene->mMeshes[am];
|
|
||||||
for (uint32_t i = 0; i < aMesh->mNumBones; i++)
|
|
||||||
{
|
|
||||||
const aiBone* bone = aMesh->mBones[i];
|
|
||||||
if (std::string boneName = bone->mName.C_Str(); m_NameToIndex.find(boneName) == m_NameToIndex.end())
|
|
||||||
{
|
|
||||||
const auto boneIndex = (uint32_t)m_Bones.size();
|
|
||||||
BoneInfo bi;
|
|
||||||
bi.Name = boneName;
|
|
||||||
bi.InverseTransform = Mat4FromAssimpMat4(bone->mOffsetMatrix);
|
|
||||||
bi.ParentIndex = -1; // 稍后设置
|
|
||||||
|
|
||||||
m_Bones.push_back(bi);
|
|
||||||
m_NameToIndex[boneName] = boneIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置骨骼的父子关系及默认局部变换(遍历节点树)
|
|
||||||
std::unordered_map<std::string, uint32_t>& nameToIdx = m_NameToIndex;
|
|
||||||
std::function<void(aiNode*, int)> traverseNodes = [&](const aiNode* node, const int parentBoneIdx)
|
|
||||||
{
|
|
||||||
const std::string nodeName = node->mName.C_Str();
|
|
||||||
const auto it = nameToIdx.find(nodeName);
|
|
||||||
int currentBoneIdx = -1;
|
|
||||||
if (it != nameToIdx.end())
|
|
||||||
{
|
|
||||||
currentBoneIdx = (int)it->second;
|
|
||||||
BoneInfo& bone = m_Bones[currentBoneIdx];
|
|
||||||
bone.ParentIndex = parentBoneIdx;
|
|
||||||
// 存储默认局部变换(绑定姿势下相对于父节点的变换)
|
|
||||||
bone.LocalBindPose = Mat4FromAssimpMat4(node->mTransformation);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < node->mNumChildren; i++)
|
|
||||||
{
|
|
||||||
traverseNodes(node->mChildren[i], currentBoneIdx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
traverseNodes(scene->mRootNode, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Skeleton::GetBoneIndex(const std::string& name) const
|
|
||||||
{
|
|
||||||
const auto it = m_NameToIndex.find(name);
|
|
||||||
return (it != m_NameToIndex.end()) ? it->second : static_cast<uint32_t>(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/3/9.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef PRISM_SKELETON_H
|
|
||||||
#define PRISM_SKELETON_H
|
|
||||||
#include "glm/glm.hpp"
|
|
||||||
#include "Prism/Asset/Asset.h"
|
|
||||||
|
|
||||||
struct aiScene;
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
struct BoneInfo
|
|
||||||
{
|
|
||||||
std::string Name;
|
|
||||||
int ParentIndex; // -1 is Root
|
|
||||||
glm::mat4 LocalBindPose;
|
|
||||||
glm::mat4 InverseTransform; // aiScene::mOffsetMatrix
|
|
||||||
};
|
|
||||||
|
|
||||||
class PRISM_API Skeleton : public Asset
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Skeleton(const aiScene* scene);
|
|
||||||
uint32_t GetBoneIndex(const std::string& name) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::vector<BoneInfo> m_Bones;
|
|
||||||
std::unordered_map<std::string, uint32_t> m_NameToIndex;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif //PRISM_SKELETON_H
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/2/3.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef PRISM_ASSET_H
|
|
||||||
#define PRISM_ASSET_H
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
#include "Prism/Core/UUID.h"
|
|
||||||
#include "Prism/Core/Ref.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
class Texture2D;
|
|
||||||
class Shader;
|
|
||||||
class MaterialInstance;
|
|
||||||
|
|
||||||
enum class AssetType
|
|
||||||
{
|
|
||||||
Scene = 0, Mesh, Texture, EnvMap, Audio, Script, Material, PhysicsMaterial, Directory, Other, None
|
|
||||||
};
|
|
||||||
|
|
||||||
using AssetHandle = UUID;
|
|
||||||
|
|
||||||
class PRISM_API Asset : public RefCounted
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AssetHandle Handle;
|
|
||||||
AssetType Type = AssetType::None;
|
|
||||||
|
|
||||||
std::string FilePath;
|
|
||||||
std::string FileName;
|
|
||||||
std::string Extension;
|
|
||||||
AssetHandle ParentDirectory;
|
|
||||||
|
|
||||||
bool IsDataLoaded = false;
|
|
||||||
|
|
||||||
virtual ~Asset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PRISM_API PhysicsMaterialAsset : public Asset
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
float StaticFriction;
|
|
||||||
float DynamicFriction;
|
|
||||||
float Bounciness;
|
|
||||||
|
|
||||||
PhysicsMaterialAsset();
|
|
||||||
|
|
||||||
PhysicsMaterialAsset(const float staticFriction, const float dynamicFriction, const float bounciness);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Treating directories as assets simplifies the asset manager window rendering by a lot
|
|
||||||
class Directory : public Asset
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::vector<AssetHandle> ChildDirectories;
|
|
||||||
|
|
||||||
Directory()
|
|
||||||
{
|
|
||||||
Type = AssetType::Directory;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,440 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/2/13.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "AssetSerializer.h"
|
|
||||||
|
|
||||||
#include "AssetsManager.h"
|
|
||||||
#include "Prism/Utilities/StringUtils.h"
|
|
||||||
#include "Prism/Utilities/FileSystem.h"
|
|
||||||
#include "Prism/Renderer/Mesh.h"
|
|
||||||
#include "Prism/Renderer/SceneEnvironment.h"
|
|
||||||
#include "Prism/Renderer/SceneRenderer.h"
|
|
||||||
|
|
||||||
#include "yaml-cpp/yaml.h"
|
|
||||||
#include "Prism/Utilities/SerializeUtils.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
void AssetSerializer::SerializeAsset(const Ref<Asset>& asset, AssetType type)
|
|
||||||
{
|
|
||||||
YAML::Emitter out;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case AssetType::Texture:
|
|
||||||
case AssetType::EnvMap:
|
|
||||||
case AssetType::Audio:
|
|
||||||
case AssetType::Script:
|
|
||||||
case AssetType::Directory:
|
|
||||||
case AssetType::Other:
|
|
||||||
case AssetType::None:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
out << YAML::BeginMap;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case Prism::AssetType::PhysicsMaterial:
|
|
||||||
{
|
|
||||||
Ref<PhysicsMaterialAsset> physicsMaterial = Ref<PhysicsMaterialAsset>(asset);
|
|
||||||
out << YAML::Key << "StaticFriction" << physicsMaterial->StaticFriction;
|
|
||||||
out << YAML::Key << "DynamicFriction" << physicsMaterial->DynamicFriction;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out << YAML::EndMap;
|
|
||||||
|
|
||||||
PM_CORE_INFO("Save Asset change...");
|
|
||||||
std::ofstream fout(asset->FilePath);
|
|
||||||
fout << out.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<Asset> AssetSerializer::DeserializeYAML(const Ref<Asset>& asset)
|
|
||||||
{
|
|
||||||
const std::ifstream stream(asset->FilePath);
|
|
||||||
std::stringstream strStream;
|
|
||||||
strStream << stream.rdbuf();
|
|
||||||
|
|
||||||
YAML::Node data = YAML::Load(strStream.str());
|
|
||||||
|
|
||||||
switch (asset->Type)
|
|
||||||
{
|
|
||||||
case AssetType::PhysicsMaterial:
|
|
||||||
{
|
|
||||||
float staticFriction = data["StaticFriction"].as<float>();
|
|
||||||
float dynamicFriction = data["DynamicFriction"].as<float>();
|
|
||||||
float bounciness = data["Bounciness"].as<float>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Ref<Asset> AssetSerializer::LoadAssetInfo(const std::string& filepath, AssetHandle parentHandle, AssetType type)
|
|
||||||
{
|
|
||||||
Ref<Asset> asset;
|
|
||||||
|
|
||||||
if (type == AssetType::Directory)
|
|
||||||
asset = Ref<Directory>::Create();
|
|
||||||
else
|
|
||||||
asset = Ref<Asset>::Create();
|
|
||||||
|
|
||||||
|
|
||||||
const std::string extension = Utils::GetExtension(filepath);
|
|
||||||
asset->FilePath = filepath;
|
|
||||||
asset->Type = type;
|
|
||||||
|
|
||||||
std::replace(asset->FilePath.begin(), asset->FilePath.end(), '\\', '/');
|
|
||||||
|
|
||||||
const bool hasMeta = FileSystem::Exists(asset->FilePath + ".meta");
|
|
||||||
if (hasMeta)
|
|
||||||
{
|
|
||||||
LoadMetaData(asset);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
asset->Handle = AssetHandle();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: file or directory Type to fix
|
|
||||||
asset->Extension = extension;
|
|
||||||
asset->FileName = Utils::RemoveExtension(Utils::GetFilename(filepath));
|
|
||||||
asset->ParentDirectory = parentHandle;
|
|
||||||
asset->IsDataLoaded = false;
|
|
||||||
|
|
||||||
#ifndef PRISM_RUNTIME
|
|
||||||
if (!hasMeta)
|
|
||||||
CreateMetaFile(asset);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<Asset> AssetSerializer::LoadAssetData(Ref<Asset>& asset)
|
|
||||||
{
|
|
||||||
if (asset->Type == AssetType::Directory)
|
|
||||||
return asset;
|
|
||||||
|
|
||||||
Ref<Asset> temp = asset;
|
|
||||||
bool loadYAMLData = true;
|
|
||||||
|
|
||||||
switch (asset->Type)
|
|
||||||
{
|
|
||||||
case AssetType::Mesh:
|
|
||||||
{
|
|
||||||
if (asset->Extension != "blend")
|
|
||||||
asset = Ref<Mesh>::Create(asset->FilePath);
|
|
||||||
loadYAMLData = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::Texture:
|
|
||||||
{
|
|
||||||
asset = Texture2D::Create(asset->FilePath);
|
|
||||||
loadYAMLData = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::EnvMap:
|
|
||||||
{
|
|
||||||
auto [radiance, irradiance] = SceneRenderer::CreateEnvironmentMap(asset->FilePath);
|
|
||||||
asset = Ref<Environment>::Create(radiance, irradiance);
|
|
||||||
loadYAMLData = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::Scene:
|
|
||||||
case AssetType::Audio:
|
|
||||||
case AssetType::Script:
|
|
||||||
case AssetType::Other:
|
|
||||||
{
|
|
||||||
loadYAMLData = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::PhysicsMaterial:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadYAMLData)
|
|
||||||
{
|
|
||||||
asset = DeserializeYAML(asset);
|
|
||||||
PM_CORE_ASSERT(asset, "Failed to load asset");
|
|
||||||
}
|
|
||||||
|
|
||||||
asset->Handle = temp->Handle;
|
|
||||||
asset->FilePath = temp->FilePath;
|
|
||||||
asset->FileName = temp->FileName;
|
|
||||||
asset->Extension = temp->Extension;
|
|
||||||
asset->ParentDirectory = temp->ParentDirectory;
|
|
||||||
asset->Type = temp->Type;
|
|
||||||
asset->IsDataLoaded = true;
|
|
||||||
|
|
||||||
return asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AssetSerializer::LoadMetaData(Ref<Asset>& asset)
|
|
||||||
{
|
|
||||||
std::ifstream stream(asset->FilePath + ".meta");
|
|
||||||
std::stringstream strStream;
|
|
||||||
strStream << stream.rdbuf();
|
|
||||||
|
|
||||||
YAML::Node data = YAML::Load(strStream.str());
|
|
||||||
if (!data["Asset"])
|
|
||||||
{
|
|
||||||
PM_CORE_ASSERT("Invalid File Format");
|
|
||||||
}
|
|
||||||
|
|
||||||
asset->Handle = data["Asset"].as<uint64_t>();
|
|
||||||
asset->FilePath = data["FilePath"].as<std::string>();
|
|
||||||
asset->Type = (AssetType)data["Type"].as<int>();
|
|
||||||
|
|
||||||
if (asset->FileName == "assets" && asset->Handle == 0)
|
|
||||||
{
|
|
||||||
asset->Handle = AssetHandle();
|
|
||||||
#ifndef PRISM_RUNTIME
|
|
||||||
CreateMetaFile(asset);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetSerializer::CreateMetaFile(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();
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/2/13.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef PRISM_ASSETSERIALIZER_H
|
|
||||||
#define PRISM_ASSETSERIALIZER_H
|
|
||||||
|
|
||||||
#include "Asset.h"
|
|
||||||
#include "Prism/Core/Ref.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
class PRISM_API AssetSerializer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template<typename T>
|
|
||||||
static void SerializeAsset(const Ref<T>& asset)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of<Asset, T>::value, "SerializeAsset only accepts types that inherit from Asset");
|
|
||||||
SerializeAsset(asset, asset->Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Ref<Asset> LoadAssetInfo(const std::string& filepath, AssetHandle parentHandle, AssetType type);
|
|
||||||
static Ref<Asset> LoadAssetData(Ref<Asset>& asset);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void SerializeAsset(const Ref<Asset>& asset, AssetType type);
|
|
||||||
static Ref<Asset> DeserializeYAML(const Ref<Asset>& asset);
|
|
||||||
static void LoadMetaData(Ref<Asset>& asset);
|
|
||||||
static void CreateMetaFile(const Ref<Asset>& asset);
|
|
||||||
static void UpdateMetaFile(const Ref<Asset>& asset);
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class AssetsManager;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif //PRISM_ASSETSERIALIZER_H
|
|
||||||
@ -1,449 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/1/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "AssetsManager.h"
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "Prism/Core/Log.h"
|
|
||||||
#include "Prism/Renderer/Mesh.h"
|
|
||||||
|
|
||||||
#include <yaml-cpp/yaml.h>
|
|
||||||
|
|
||||||
#include "AssetSerializer.h"
|
|
||||||
#include "Prism/Core/Application.h"
|
|
||||||
#include "Prism/Renderer/SceneEnvironment.h"
|
|
||||||
#include "Prism/Utilities/StringUtils.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
void AssetTypes::Init()
|
|
||||||
{
|
|
||||||
s_Types["scene"] = AssetType::Scene;
|
|
||||||
s_Types["pmx"] = AssetType::Mesh;
|
|
||||||
s_Types["fbx"] = AssetType::Mesh;
|
|
||||||
s_Types["dae"] = AssetType::Mesh;
|
|
||||||
s_Types["obj"] = AssetType::Mesh;
|
|
||||||
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["hdr"] = AssetType::EnvMap;
|
|
||||||
s_Types["blend"] = AssetType::Mesh;
|
|
||||||
s_Types["pmat"] = AssetType::Material;
|
|
||||||
s_Types["hpm"] = AssetType::PhysicsMaterial;
|
|
||||||
s_Types["wav"] = AssetType::Audio;
|
|
||||||
s_Types["ogg"] = AssetType::Audio;
|
|
||||||
s_Types["cs"] = AssetType::Script;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetType AssetTypes::GetAssetTypeFromExtension(const std::string& extension)
|
|
||||||
{
|
|
||||||
return s_Types.find(extension) != s_Types.end() ? s_Types[extension] : AssetType::Other;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, AssetType> AssetTypes::s_Types;
|
|
||||||
AssetsManager::AssetsChangeEventFn AssetsManager::s_AssetsChangeCallback = nullptr;
|
|
||||||
std::unordered_map<AssetHandle, Ref<Asset>> AssetsManager::s_LoadedAssets;
|
|
||||||
|
|
||||||
void AssetsManager::Init()
|
|
||||||
{
|
|
||||||
FileSystem::SetChangeCallback(OnFileSystemChanged);
|
|
||||||
ReloadAssets();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManager::SetAssetChangeCallback(const AssetsChangeEventFn& callback)
|
|
||||||
{
|
|
||||||
s_AssetsChangeCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManager::Shutdown()
|
|
||||||
{
|
|
||||||
s_LoadedAssets.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Ref<Asset>> AssetsManager::GetAssetsInDirectory(AssetHandle directoryHandle)
|
|
||||||
{
|
|
||||||
std::vector<Ref<Asset>> results;
|
|
||||||
|
|
||||||
for (const auto& asset : s_LoadedAssets)
|
|
||||||
{
|
|
||||||
if (asset.second && asset.second->ParentDirectory == directoryHandle && asset.second->Handle != directoryHandle)
|
|
||||||
results.push_back(asset.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<Ref<Asset>> AssetsManager::SearchFiles(const std::string& query, const std::string& searchPath)
|
|
||||||
{
|
|
||||||
std::vector<Ref<Asset>> results;
|
|
||||||
|
|
||||||
if (!searchPath.empty())
|
|
||||||
{
|
|
||||||
for (const auto&[key, asset] : s_LoadedAssets)
|
|
||||||
{
|
|
||||||
if (asset->FileName.find(query) != std::string::npos && asset->FilePath.find(searchPath) != std::string::npos)
|
|
||||||
{
|
|
||||||
results.push_back(asset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string AssetsManager::GetParentPath(const std::string& path)
|
|
||||||
{
|
|
||||||
return std::filesystem::path(path).parent_path().string();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetsManager::IsDirectory(const std::string& filepath)
|
|
||||||
{
|
|
||||||
for (auto&[handle, asset] : s_LoadedAssets)
|
|
||||||
{
|
|
||||||
if (asset->Type == AssetType::Directory && asset->FilePath == filepath)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AssetHandle AssetsManager::GetAssetHandleFromFilePath(const std::string& filepath)
|
|
||||||
{
|
|
||||||
const std::string normalizedPath = Utils::NormalizePath(filepath);
|
|
||||||
for (auto&[id, asset] : s_LoadedAssets)
|
|
||||||
{
|
|
||||||
if (asset->FilePath == normalizedPath)
|
|
||||||
return id;
|
|
||||||
|
|
||||||
const std::string normalizedPathToLower = Utils::StringToLower(normalizedPath);
|
|
||||||
const std::string assetFilePath = Utils::StringToLower(asset->FilePath);
|
|
||||||
if (assetFilePath == normalizedPathToLower)
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetsManager::IsAssetHandleValid(const AssetHandle& assetHandle)
|
|
||||||
{
|
|
||||||
return assetHandle != 0 && s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Ref<T> AssetsManager::GetAsset(AssetHandle assetHandle, bool loadData)
|
|
||||||
{
|
|
||||||
PM_CORE_ASSERT(s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end());
|
|
||||||
Ref<Asset> asset = s_LoadedAssets[assetHandle];
|
|
||||||
|
|
||||||
if (!asset->IsDataLoaded && loadData)
|
|
||||||
{
|
|
||||||
asset = AssetSerializer::LoadAssetData(asset);
|
|
||||||
s_LoadedAssets[assetHandle] = asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
return asset.As<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template PRISM_API Ref<Asset> AssetsManager::GetAsset(AssetHandle, bool);
|
|
||||||
template PRISM_API Ref<Mesh> 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<Directory> AssetsManager::GetAsset(AssetHandle, bool);
|
|
||||||
template PRISM_API Ref<Texture2D> AssetsManager::GetAsset(AssetHandle, bool);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Ref<T> AssetsManager::GetAsset(const std::string& filepath, const bool loadData)
|
|
||||||
{
|
|
||||||
return GetAsset<T>(GetAssetHandleFromFilePath(filepath), loadData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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<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<Directory> AssetsManager::GetAsset(const std::string&, bool);
|
|
||||||
template PRISM_API Ref<Texture2D> AssetsManager::GetAsset(const std::string&, bool);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Ref<T> AssetsManager::TryGetAsset(const std::string& filepath, const bool loadData)
|
|
||||||
{
|
|
||||||
AssetHandle assetHandle = GetAssetHandleFromFilePath(filepath);
|
|
||||||
if (!assetHandle) return Ref<T>();
|
|
||||||
return GetAsset<T>(assetHandle, loadData);
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
Ref<Asset> asset = s_LoadedAssets[assetHandle];
|
|
||||||
if (asset->Type == AssetType::Directory)
|
|
||||||
{
|
|
||||||
if (IsAssetHandleValid(asset->ParentDirectory))
|
|
||||||
{
|
|
||||||
auto& childList = s_LoadedAssets[asset->ParentDirectory].As<Directory>()->ChildDirectories;
|
|
||||||
childList.erase(std::remove(childList.begin(), childList.end(), assetHandle), childList.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto child : asset.As<Directory>()->ChildDirectories)
|
|
||||||
RemoveAsset(child);
|
|
||||||
|
|
||||||
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); )
|
|
||||||
{
|
|
||||||
if (it->second->ParentDirectory != assetHandle)
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
it = s_LoadedAssets.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s_LoadedAssets.erase(assetHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
Ref<T> AssetsManager::CreateAsset(const std::string& filename, AssetType type, AssetHandle directoryHandle, Args&&... args)
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of_v<Asset, T>, "CreateAsset only works for types derived from Asset");
|
|
||||||
|
|
||||||
const auto& directory = GetAsset<Directory>(directoryHandle);
|
|
||||||
|
|
||||||
Ref<T> asset = Ref<T>::Create(std::forward<Args>(args)...);
|
|
||||||
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 + std::to_string(Application::Get().GetTime()));
|
|
||||||
|
|
||||||
asset->IsDataLoaded = true;
|
|
||||||
s_LoadedAssets[asset->Handle] = asset;
|
|
||||||
|
|
||||||
AssetSerializer::SerializeAsset(asset);
|
|
||||||
AssetSerializer::CreateMetaFile(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)
|
|
||||||
{
|
|
||||||
return s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end() && s_LoadedAssets[assetHandle]->Type == type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string AssetsManager::StripExtras(const std::string& filename)
|
|
||||||
{
|
|
||||||
std::vector<std::string> out;
|
|
||||||
size_t start;
|
|
||||||
size_t end = 0;
|
|
||||||
|
|
||||||
while ((start = filename.find_first_not_of('.', end)) != std::string::npos)
|
|
||||||
{
|
|
||||||
end = filename.find('.', start);
|
|
||||||
out.push_back(filename.substr(start, end - start));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out[0].length() >= 10)
|
|
||||||
{
|
|
||||||
auto cutFilename = out[0].substr(0, 9) + "...";
|
|
||||||
return cutFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto filenameLength = out[0].length();
|
|
||||||
const auto paddingToAdd = 9 - filenameLength;
|
|
||||||
|
|
||||||
std::string newFileName;
|
|
||||||
|
|
||||||
for (int i = 0; i <= paddingToAdd; i++)
|
|
||||||
{
|
|
||||||
newFileName += " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
newFileName += out[0];
|
|
||||||
|
|
||||||
return newFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<Asset> AssetsManager::ImportAsset(const std::string& filepath, AssetHandle parentHandle)
|
|
||||||
{
|
|
||||||
const std::string extension = Utils::GetExtension(filepath);
|
|
||||||
if (extension == "meta")
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const AssetType type = AssetTypes::GetAssetTypeFromExtension(extension);
|
|
||||||
Ref<Asset> asset = AssetSerializer::LoadAssetInfo(filepath, parentHandle, type);
|
|
||||||
if (s_LoadedAssets.find(asset->Handle) != s_LoadedAssets.end())
|
|
||||||
{
|
|
||||||
if (s_LoadedAssets[asset->Handle]->IsDataLoaded)
|
|
||||||
{
|
|
||||||
asset = AssetSerializer::LoadAssetData(asset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s_LoadedAssets[asset->Handle] = asset;
|
|
||||||
|
|
||||||
return asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Ref<Asset> AssetsManager::ProcessDirectory(const std::string& directoryPath, AssetHandle parentHandle)
|
|
||||||
{
|
|
||||||
Ref<Directory> dirInfo = AssetSerializer::LoadAssetInfo(directoryPath, parentHandle, AssetType::Directory).As<Directory>();
|
|
||||||
s_LoadedAssets[dirInfo->Handle] = dirInfo;
|
|
||||||
|
|
||||||
if (IsAssetHandleValid(parentHandle))
|
|
||||||
s_LoadedAssets[parentHandle].As<Directory>()->ChildDirectories.push_back(dirInfo->Handle);
|
|
||||||
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(directoryPath))
|
|
||||||
{
|
|
||||||
if (entry.is_directory())
|
|
||||||
ProcessDirectory(entry.path().string(), dirInfo->Handle);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Ref<Asset> asset = ImportAsset(entry.path().string(), dirInfo->Handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dirInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<Asset> AssetsManager::ReloadAssets()
|
|
||||||
{
|
|
||||||
return ProcessDirectory("assets", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManager::OnFileSystemChanged(FileSystemChangedEvent e)
|
|
||||||
{
|
|
||||||
e.NewName = Utils::RemoveExtension(e.NewName);
|
|
||||||
e.OldName = Utils::RemoveExtension(e.OldName);
|
|
||||||
|
|
||||||
const AssetHandle parentHandle = FindParentHandle(e.FilePath);
|
|
||||||
|
|
||||||
if (std::filesystem::path(e.FilePath).extension() != ".meta")
|
|
||||||
{
|
|
||||||
switch (e.Action)
|
|
||||||
{
|
|
||||||
case FileSystemAction::Added:
|
|
||||||
{
|
|
||||||
if (e.IsDirectory)
|
|
||||||
ProcessDirectory(e.FilePath, parentHandle);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AssetHandle assetHandle = GetAssetHandleFromFilePath(e.FilePath);
|
|
||||||
if (!assetHandle)
|
|
||||||
ImportAsset(e.FilePath, parentHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FileSystemAction::Modified:
|
|
||||||
{
|
|
||||||
if (!e.IsDirectory)
|
|
||||||
{
|
|
||||||
Ref<Asset> asset = ImportAsset(e.FilePath, parentHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FileSystemAction::Rename:
|
|
||||||
{
|
|
||||||
Ref<Asset> asset = nullptr;
|
|
||||||
{
|
|
||||||
const std::string oldFilePath = Utils::ReplaceFilePathName(e.FilePath, e.OldName);
|
|
||||||
for (auto& [handle, existingAsset] : s_LoadedAssets)
|
|
||||||
{
|
|
||||||
if (existingAsset->FilePath == oldFilePath)
|
|
||||||
{
|
|
||||||
asset = existingAsset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asset)
|
|
||||||
{
|
|
||||||
std::string extension = Utils::GetExtension(asset->FilePath);
|
|
||||||
std::string oldMetaPath = asset->FilePath + ".meta";
|
|
||||||
|
|
||||||
FileSystem::Rename(oldMetaPath, e.NewName + "." + extension);
|
|
||||||
|
|
||||||
asset->FilePath = e.FilePath;
|
|
||||||
asset->FileName = e.NewName;
|
|
||||||
asset->Extension = extension;
|
|
||||||
|
|
||||||
AssetSerializer::UpdateMetaFile(asset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FileSystemAction::Delete:
|
|
||||||
{
|
|
||||||
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
|
|
||||||
{
|
|
||||||
std::string filePath = Utils::NormalizePath(it->second->FilePath);
|
|
||||||
std::string eFilePath = Utils::NormalizePath(e.FilePath);
|
|
||||||
if (filePath != eFilePath)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
RemoveAsset(it->first);
|
|
||||||
FileSystem::PrismDeleteFile(eFilePath + ".meta");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (s_AssetsChangeCallback)
|
|
||||||
s_AssetsChangeCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetHandle AssetsManager::FindParentHandleInChildren(Ref<Directory>& dir, const std::string& dirName)
|
|
||||||
{
|
|
||||||
if (dir->FileName == dirName)
|
|
||||||
return dir->Handle;
|
|
||||||
|
|
||||||
for (const AssetHandle& childHandle : dir->ChildDirectories)
|
|
||||||
{
|
|
||||||
Ref<Directory> child = GetAsset<Directory>(childHandle);
|
|
||||||
AssetHandle dirHandle = FindParentHandleInChildren(child, dirName);
|
|
||||||
|
|
||||||
if (IsAssetHandleValid(dirHandle))
|
|
||||||
return dirHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetHandle AssetsManager::FindParentHandle(const std::string& filepath)
|
|
||||||
{
|
|
||||||
const std::vector<std::string> parts = Utils::SplitString(filepath, "/\\");
|
|
||||||
const std::string& parentFolder = parts[parts.size() - 2];
|
|
||||||
Ref<Directory> assetsDirectory = GetAsset<Directory>(GetAssetHandleFromFilePath("assets"));
|
|
||||||
return FindParentHandleInChildren(assetsDirectory, parentFolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/1/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef PRISM_ASSETSMANAGER_H
|
|
||||||
#define PRISM_ASSETSMANAGER_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "Asset.h"
|
|
||||||
#include "Prism/Utilities/FileSystem.h"
|
|
||||||
#include "Prism/Core/Ref.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
|
|
||||||
class AssetTypes
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void Init();
|
|
||||||
static AssetType GetAssetTypeFromExtension(const std::string& extension);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::map<std::string, AssetType> s_Types;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PRISM_API AssetsManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using AssetsChangeEventFn = std::function<void()>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static void Init();
|
|
||||||
static void SetAssetChangeCallback(const AssetsChangeEventFn& callback);
|
|
||||||
static void Shutdown();
|
|
||||||
|
|
||||||
static std::vector<Ref<Asset>> GetAssetsInDirectory(AssetHandle directoryHandle);
|
|
||||||
|
|
||||||
static std::vector<Ref<Asset>> SearchFiles(const std::string& query, const std::string& searchPath);
|
|
||||||
|
|
||||||
static std::string GetParentPath(const std::string& path);
|
|
||||||
|
|
||||||
static bool IsDirectory(const std::string& filepath);
|
|
||||||
|
|
||||||
static AssetHandle GetAssetHandleFromFilePath(const std::string& filepath);
|
|
||||||
static bool IsAssetHandleValid(const AssetHandle& assetHandle);
|
|
||||||
|
|
||||||
|
|
||||||
static Ref<PhysicsMaterialAsset> CreateAssetPhysicsMaterial(const std::string& filename, AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3);
|
|
||||||
|
|
||||||
static void RemoveAsset(AssetHandle assetHandle);
|
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
static Ref<T> CreateAsset(const std::string& filename, AssetType type, AssetHandle directoryHandle, Args&&... args);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static Ref<T> GetAsset(AssetHandle assetHandle, bool loadData = true);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
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 std::string StripExtras(const std::string& filename);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
static Ref<Asset> ImportAsset(const std::string& filepath, AssetHandle parentHandle);
|
|
||||||
static Ref<Asset> ProcessDirectory(const std::string& directoryPath, AssetHandle parentHandle);
|
|
||||||
/**
|
|
||||||
* this will load from projectPath all assets, and return the root Asset Ref
|
|
||||||
* @param projectPath assets path
|
|
||||||
* @return the root asset Ref
|
|
||||||
*/
|
|
||||||
static Ref<Asset> ReloadAssets();
|
|
||||||
|
|
||||||
static void OnFileSystemChanged(FileSystemChangedEvent e);
|
|
||||||
|
|
||||||
static AssetHandle FindParentHandleInChildren(Ref<Directory>& dir, const std::string& dirName);
|
|
||||||
static AssetHandle FindParentHandle(const std::string& filepath);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::unordered_map<AssetHandle, Ref<Asset>> s_LoadedAssets;
|
|
||||||
static AssetsChangeEventFn s_AssetsChangeCallback;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif //PRISM_ASSETSMANAGER_H
|
|
||||||