add simple render, add simple pbr shader(from hazel)
3
.gitmodules
vendored
@ -11,3 +11,6 @@
|
|||||||
[submodule "Prism/vendor/glm"]
|
[submodule "Prism/vendor/glm"]
|
||||||
path = Prism/vendor/glm
|
path = Prism/vendor/glm
|
||||||
url = https://github.com/g-truc/glm.git
|
url = https://github.com/g-truc/glm.git
|
||||||
|
[submodule "Prism/vendor/assimp"]
|
||||||
|
path = Prism/vendor/assimp
|
||||||
|
url = https://github.com/assimp/assimp.git
|
||||||
|
|||||||
@ -4,11 +4,14 @@ file(GLOB_RECURSE SRC_SOURCE src/**.cpp)
|
|||||||
|
|
||||||
# ------------- configure -------------
|
# ------------- configure -------------
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
set(ASSIMP_BUILD_ZLIB ON CACHE BOOL "Build built-in zlib" FORCE)
|
||||||
|
|
||||||
add_subdirectory(vendor/spdlog EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/spdlog EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/glfw EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/glfw EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/glad EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/glad EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/glm EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/glm EXCLUDE_FROM_ALL)
|
||||||
|
add_subdirectory(vendor/assimp EXCLUDE_FROM_ALL)
|
||||||
|
add_subdirectory(vendor/stb EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
|
||||||
# ------------- imgui -------------
|
# ------------- imgui -------------
|
||||||
@ -27,6 +30,8 @@ set(LINK_LIBRARIES_PRIVATE
|
|||||||
spdlog
|
spdlog
|
||||||
glfw
|
glfw
|
||||||
glad
|
glad
|
||||||
|
assimp
|
||||||
|
stb
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LINK_LIBRARIES_PUBLIC
|
set(LINK_LIBRARIES_PUBLIC
|
||||||
@ -78,8 +83,8 @@ target_precompile_headers(${STATIC_LIBRARY} PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(${STATIC_LIBRARY} PROPERTIES
|
set_target_properties(${STATIC_LIBRARY} PROPERTIES
|
||||||
OUTPUT_NAME ${PROJECT_NAME}
|
OUTPUT_NAME ${PROJECT_NAME}d
|
||||||
ARCHIVE_OUTPUT_NAME ${PROJECT_NAME}
|
ARCHIVE_OUTPUT_NAME ${PROJECT_NAME}d
|
||||||
)
|
)
|
||||||
|
|
||||||
# shared library
|
# shared library
|
||||||
@ -106,8 +111,8 @@ target_precompile_headers(${SHARED_LIBRARY} PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(${SHARED_LIBRARY} PROPERTIES
|
set_target_properties(${SHARED_LIBRARY} PROPERTIES
|
||||||
OUTPUT_NAME ${PROJECT_NAME}d
|
OUTPUT_NAME ${PROJECT_NAME}
|
||||||
LIBRARY_OUTPUT_NAME ${PROJECT_NAME}d
|
LIBRARY_OUTPUT_NAME ${PROJECT_NAME}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,13 @@
|
|||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
#include "Prism/Renderer/Renderer.h"
|
#include "Prism/Renderer/Renderer.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "Prism/Renderer/FrameBuffer.h"
|
||||||
|
#include "Prism/Renderer/RendererAPI.h"
|
||||||
|
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
#include <GLFW/glfw3native.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -74,11 +80,45 @@ namespace Prism
|
|||||||
void Application::RenderImGui()
|
void Application::RenderImGui()
|
||||||
{
|
{
|
||||||
m_ImGuiLayer->Begin();
|
m_ImGuiLayer->Begin();
|
||||||
|
|
||||||
|
ImGui::Begin("Renderer");
|
||||||
|
auto& caps = RendererAPI::GetCapabilities();
|
||||||
|
ImGui::Text("Vendor: %s", caps.Vendor.c_str());
|
||||||
|
ImGui::Text("Renderer: %s", caps.Renderer.c_str());
|
||||||
|
ImGui::Text("Version: %s", caps.Version.c_str());
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
for (Layer* layer : m_LayerStack)
|
for (Layer* layer : m_LayerStack)
|
||||||
layer->OnImGuiRender();
|
layer->OnImGuiRender();
|
||||||
|
|
||||||
m_ImGuiLayer->End();
|
m_ImGuiLayer->End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Application::OpenFile(const std::string& filter) const
|
||||||
|
{
|
||||||
|
OPENFILENAMEA ofn; // common dialog box structure
|
||||||
|
CHAR szFile[260] = { 0 }; // if using TCHAR macros
|
||||||
|
|
||||||
|
// Initialize OPENFILENAME
|
||||||
|
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
||||||
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||||
|
ofn.hwndOwner = glfwGetWin32Window((GLFWwindow*)m_Window->GetNativeWindow());
|
||||||
|
ofn.lpstrFile = szFile;
|
||||||
|
ofn.nMaxFile = sizeof(szFile);
|
||||||
|
ofn.lpstrFilter = "All\0*.*\0";
|
||||||
|
ofn.nFilterIndex = 1;
|
||||||
|
ofn.lpstrFileTitle = NULL;
|
||||||
|
ofn.nMaxFileTitle = 0;
|
||||||
|
ofn.lpstrInitialDir = NULL;
|
||||||
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
||||||
|
|
||||||
|
if (GetOpenFileNameA(&ofn) == TRUE)
|
||||||
|
{
|
||||||
|
return ofn.lpstrFile;
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
void Application::PushLayer(Layer* layer)
|
void Application::PushLayer(Layer* layer)
|
||||||
{
|
{
|
||||||
m_LayerStack.PushLayer(layer);
|
m_LayerStack.PushLayer(layer);
|
||||||
@ -93,6 +133,11 @@ namespace Prism
|
|||||||
|
|
||||||
bool Application::OnWindowResize(const WindowResizeEvent& e)
|
bool Application::OnWindowResize(const WindowResizeEvent& e)
|
||||||
{
|
{
|
||||||
|
int width = e.GetWidth(), height = e.GetHeight();
|
||||||
|
PM_RENDER_2(width, height, { glViewport(0, 0, width, height); });
|
||||||
|
auto& fbs = FrameBufferPool::GetGlobal()->GetAll();
|
||||||
|
for (auto& fb : fbs)
|
||||||
|
fb->Resize(width, height);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,8 @@ namespace Prism
|
|||||||
|
|
||||||
void RenderImGui();
|
void RenderImGui();
|
||||||
|
|
||||||
|
std::string OpenFile(const std::string& filter) const;
|
||||||
|
|
||||||
inline Window& GetWindow() { return *m_Window; }
|
inline Window& GetWindow() { return *m_Window; }
|
||||||
|
|
||||||
inline static Application& Get() { return *s_Instance; }
|
inline static Application& Get() { return *s_Instance; }
|
||||||
|
|||||||
@ -23,8 +23,10 @@ namespace Prism {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#if defined(_WIN32)
|
|
||||||
|
|
||||||
|
#ifdef PRISM_SHARED
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE hModule,
|
BOOL APIENTRY DllMain(HMODULE hModule,
|
||||||
DWORD ul_reason_for_call,
|
DWORD ul_reason_for_call,
|
||||||
@ -60,3 +62,5 @@ static void library_unload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -22,6 +22,11 @@
|
|||||||
#else
|
#else
|
||||||
#define PRISM_API
|
#define PRISM_API
|
||||||
#define IMGUI_API
|
#define IMGUI_API
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
void InitializeCore();
|
||||||
|
void ShutdownCore();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BIT(x) (1 << x)
|
#define BIT(x) (1 << x)
|
||||||
|
|||||||
@ -11,9 +11,18 @@ extern Prism::Application* Prism::CreateApplication();
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
#ifndef PRISM_SHARED
|
||||||
|
Prism::InitializeCore();
|
||||||
|
#endif
|
||||||
|
|
||||||
Prism::Application* app = Prism::CreateApplication();
|
Prism::Application* app = Prism::CreateApplication();
|
||||||
app->Run();
|
app->Run();
|
||||||
delete app;
|
delete app;
|
||||||
|
|
||||||
|
#ifndef PRISM_SHARED
|
||||||
|
Prism::ShutdownCore();
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //ENTRYPOINT_H
|
#endif //ENTRYPOINT_H
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#define KEYEVENT_H
|
#define KEYEVENT_H
|
||||||
|
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
|
#include "KeyEvent.h"
|
||||||
|
|
||||||
namespace Prism {
|
namespace Prism {
|
||||||
|
|
||||||
|
|||||||
@ -66,6 +66,10 @@ namespace Prism
|
|||||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||||
|
|
||||||
|
|
||||||
|
ImFont* pFont = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\segoeui.ttf)", 18.0f);
|
||||||
|
io.FontDefault = io.Fonts->Fonts.back();
|
||||||
|
|
||||||
// Setup Dear ImGui style
|
// Setup Dear ImGui style
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
//ImGui::StyleColorsClassic();
|
//ImGui::StyleColorsClassic();
|
||||||
@ -77,6 +81,7 @@ namespace Prism
|
|||||||
style.WindowRounding = 0.0f;
|
style.WindowRounding = 0.0f;
|
||||||
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
||||||
}
|
}
|
||||||
|
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.15f, 0.15f, 0.15f, style.Colors[ImGuiCol_WindowBg].w);
|
||||||
|
|
||||||
Application& app = Application::Get();
|
Application& app = Application::Get();
|
||||||
const auto window = static_cast<GLFWwindow*>(app.GetWindow().GetNativeWindow());
|
const auto window = static_cast<GLFWwindow*>(app.GetWindow().GetNativeWindow());
|
||||||
|
|||||||
@ -10,11 +10,11 @@ namespace Prism
|
|||||||
class Input
|
class Input
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool IsKeyPressed(int keycode) { return s_Instance->IsKeyPressed(keycode); }
|
static bool IsKeyPressed(const int keycode) { return s_Instance->IsKeyPressedImpl(keycode); }
|
||||||
|
|
||||||
inline static bool IsMouseButtonPressed(int button) { return s_Instance->IsMouseButtonPressed(button); }
|
inline static bool IsMouseButtonPressed(const int button) { return s_Instance->IsMouseButtonPressedImpl(button); }
|
||||||
inline static float GetMouseX() { return s_Instance->GetMouseX(); }
|
inline static float GetMouseX() { return s_Instance->GetMouseXImpl(); }
|
||||||
inline static float GetMouseY() { return s_Instance->GetMouseY(); }
|
inline static float GetMouseY() { return s_Instance->GetMouseYImpl(); }
|
||||||
protected:
|
protected:
|
||||||
virtual bool IsKeyPressedImpl(int keycode) = 0;
|
virtual bool IsKeyPressedImpl(int keycode) = 0;
|
||||||
virtual bool IsMouseButtonPressedImpl(int button) = 0;
|
virtual bool IsMouseButtonPressedImpl(int button) = 0;
|
||||||
|
|||||||
134
Prism/src/Prism/Core/KeyCodes.h
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef KEYCODES_H
|
||||||
|
#define KEYCODES_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// From glfw3.h
|
||||||
|
#define HZ_KEY_SPACE 32
|
||||||
|
#define HZ_KEY_APOSTROPHE 39 /* ' */
|
||||||
|
#define HZ_KEY_COMMA 44 /* , */
|
||||||
|
#define HZ_KEY_MINUS 45 /* - */
|
||||||
|
#define HZ_KEY_PERIOD 46 /* . */
|
||||||
|
#define HZ_KEY_SLASH 47 /* / */
|
||||||
|
#define HZ_KEY_0 48
|
||||||
|
#define HZ_KEY_1 49
|
||||||
|
#define HZ_KEY_2 50
|
||||||
|
#define HZ_KEY_3 51
|
||||||
|
#define HZ_KEY_4 52
|
||||||
|
#define HZ_KEY_5 53
|
||||||
|
#define HZ_KEY_6 54
|
||||||
|
#define HZ_KEY_7 55
|
||||||
|
#define HZ_KEY_8 56
|
||||||
|
#define HZ_KEY_9 57
|
||||||
|
#define HZ_KEY_SEMICOLON 59 /* ; */
|
||||||
|
#define HZ_KEY_EQUAL 61 /* = */
|
||||||
|
#define HZ_KEY_A 65
|
||||||
|
#define HZ_KEY_B 66
|
||||||
|
#define HZ_KEY_C 67
|
||||||
|
#define HZ_KEY_D 68
|
||||||
|
#define HZ_KEY_E 69
|
||||||
|
#define HZ_KEY_F 70
|
||||||
|
#define HZ_KEY_G 71
|
||||||
|
#define HZ_KEY_H 72
|
||||||
|
#define HZ_KEY_I 73
|
||||||
|
#define HZ_KEY_J 74
|
||||||
|
#define HZ_KEY_K 75
|
||||||
|
#define HZ_KEY_L 76
|
||||||
|
#define HZ_KEY_M 77
|
||||||
|
#define HZ_KEY_N 78
|
||||||
|
#define HZ_KEY_O 79
|
||||||
|
#define HZ_KEY_P 80
|
||||||
|
#define HZ_KEY_Q 81
|
||||||
|
#define HZ_KEY_R 82
|
||||||
|
#define HZ_KEY_S 83
|
||||||
|
#define HZ_KEY_T 84
|
||||||
|
#define HZ_KEY_U 85
|
||||||
|
#define HZ_KEY_V 86
|
||||||
|
#define HZ_KEY_W 87
|
||||||
|
#define HZ_KEY_X 88
|
||||||
|
#define HZ_KEY_Y 89
|
||||||
|
#define HZ_KEY_Z 90
|
||||||
|
#define HZ_KEY_LEFT_BRACKET 91 /* [ */
|
||||||
|
#define HZ_KEY_BACKSLASH 92 /* \ */
|
||||||
|
#define HZ_KEY_RIGHT_BRACKET 93 /* ] */
|
||||||
|
#define HZ_KEY_GRAVE_ACCENT 96 /* ` */
|
||||||
|
#define HZ_KEY_WORLD_1 161 /* non-US #1 */
|
||||||
|
#define HZ_KEY_WORLD_2 162 /* non-US #2 */
|
||||||
|
|
||||||
|
/* Function keys */
|
||||||
|
#define HZ_KEY_ESCAPE 256
|
||||||
|
#define HZ_KEY_ENTER 257
|
||||||
|
#define HZ_KEY_TAB 258
|
||||||
|
#define HZ_KEY_BACKSPACE 259
|
||||||
|
#define HZ_KEY_INSERT 260
|
||||||
|
#define HZ_KEY_DELETE 261
|
||||||
|
#define HZ_KEY_RIGHT 262
|
||||||
|
#define HZ_KEY_LEFT 263
|
||||||
|
#define HZ_KEY_DOWN 264
|
||||||
|
#define HZ_KEY_UP 265
|
||||||
|
#define HZ_KEY_PAGE_UP 266
|
||||||
|
#define HZ_KEY_PAGE_DOWN 267
|
||||||
|
#define HZ_KEY_HOME 268
|
||||||
|
#define HZ_KEY_END 269
|
||||||
|
#define HZ_KEY_CAPS_LOCK 280
|
||||||
|
#define HZ_KEY_SCROLL_LOCK 281
|
||||||
|
#define HZ_KEY_NUM_LOCK 282
|
||||||
|
#define HZ_KEY_PRINT_SCREEN 283
|
||||||
|
#define HZ_KEY_PAUSE 284
|
||||||
|
#define HZ_KEY_F1 290
|
||||||
|
#define HZ_KEY_F2 291
|
||||||
|
#define HZ_KEY_F3 292
|
||||||
|
#define HZ_KEY_F4 293
|
||||||
|
#define HZ_KEY_F5 294
|
||||||
|
#define HZ_KEY_F6 295
|
||||||
|
#define HZ_KEY_F7 296
|
||||||
|
#define HZ_KEY_F8 297
|
||||||
|
#define HZ_KEY_F9 298
|
||||||
|
#define HZ_KEY_F10 299
|
||||||
|
#define HZ_KEY_F11 300
|
||||||
|
#define HZ_KEY_F12 301
|
||||||
|
#define HZ_KEY_F13 302
|
||||||
|
#define HZ_KEY_F14 303
|
||||||
|
#define HZ_KEY_F15 304
|
||||||
|
#define HZ_KEY_F16 305
|
||||||
|
#define HZ_KEY_F17 306
|
||||||
|
#define HZ_KEY_F18 307
|
||||||
|
#define HZ_KEY_F19 308
|
||||||
|
#define HZ_KEY_F20 309
|
||||||
|
#define HZ_KEY_F21 310
|
||||||
|
#define HZ_KEY_F22 311
|
||||||
|
#define HZ_KEY_F23 312
|
||||||
|
#define HZ_KEY_F24 313
|
||||||
|
#define HZ_KEY_F25 314
|
||||||
|
#define HZ_KEY_KP_0 320
|
||||||
|
#define HZ_KEY_KP_1 321
|
||||||
|
#define HZ_KEY_KP_2 322
|
||||||
|
#define HZ_KEY_KP_3 323
|
||||||
|
#define HZ_KEY_KP_4 324
|
||||||
|
#define HZ_KEY_KP_5 325
|
||||||
|
#define HZ_KEY_KP_6 326
|
||||||
|
#define HZ_KEY_KP_7 327
|
||||||
|
#define HZ_KEY_KP_8 328
|
||||||
|
#define HZ_KEY_KP_9 329
|
||||||
|
#define HZ_KEY_KP_DECIMAL 330
|
||||||
|
#define HZ_KEY_KP_DIVIDE 331
|
||||||
|
#define HZ_KEY_KP_MULTIPLY 332
|
||||||
|
#define HZ_KEY_KP_SUBTRACT 333
|
||||||
|
#define HZ_KEY_KP_ADD 334
|
||||||
|
#define HZ_KEY_KP_ENTER 335
|
||||||
|
#define HZ_KEY_KP_EQUAL 336
|
||||||
|
#define HZ_KEY_LEFT_SHIFT 340
|
||||||
|
#define HZ_KEY_LEFT_CONTROL 341
|
||||||
|
#define HZ_KEY_LEFT_ALT 342
|
||||||
|
#define HZ_KEY_LEFT_SUPER 343
|
||||||
|
#define HZ_KEY_RIGHT_SHIFT 344
|
||||||
|
#define HZ_KEY_RIGHT_CONTROL 345
|
||||||
|
#define HZ_KEY_RIGHT_ALT 346
|
||||||
|
#define HZ_KEY_RIGHT_SUPER 347
|
||||||
|
#define HZ_KEY_MENU 348
|
||||||
|
|
||||||
|
#endif //KEYCODES_H
|
||||||
@ -29,12 +29,10 @@ namespace Prism
|
|||||||
|
|
||||||
void OpenGLVertexBuffer::SetData(void* buffer, unsigned int size, unsigned int offset)
|
void OpenGLVertexBuffer::SetData(void* buffer, unsigned int size, unsigned int offset)
|
||||||
{
|
{
|
||||||
|
m_Size = size;
|
||||||
PM_RENDER_S3(buffer, size, offset, {
|
PM_RENDER_S3(buffer, size, offset, {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, self->m_RendererID);
|
glBindBuffer(GL_ARRAY_BUFFER, self->m_RendererID);
|
||||||
glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW);
|
||||||
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +40,11 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
PM_RENDER_S({
|
PM_RENDER_S({
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, self->m_RendererID);
|
glBindBuffer(GL_ARRAY_BUFFER, self->m_RendererID);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (const void*)(3 * sizeof(float)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +69,7 @@ namespace Prism
|
|||||||
|
|
||||||
void OpenGLIndexBuffer::SetData(void* buffer, unsigned int size, unsigned int offset)
|
void OpenGLIndexBuffer::SetData(void* buffer, unsigned int size, unsigned int offset)
|
||||||
{
|
{
|
||||||
|
m_Size = size;
|
||||||
PM_RENDER_S3(buffer, size, offset, {
|
PM_RENDER_S3(buffer, size, offset, {
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->m_RendererID);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->m_RendererID);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW);
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW);
|
||||||
|
|||||||
@ -43,6 +43,8 @@ namespace Prism
|
|||||||
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0);
|
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0);
|
||||||
virtual void Bind() const;
|
virtual void Bind() const;
|
||||||
|
|
||||||
|
virtual uint32_t GetCount() const { return m_Size / sizeof(uint32_t); }
|
||||||
|
|
||||||
virtual unsigned int GetSize() const { return m_Size; }
|
virtual unsigned int GetSize() const { return m_Size; }
|
||||||
virtual RendererID GetRendererID() const { return m_RendererID; }
|
virtual RendererID GetRendererID() const { return m_RendererID; }
|
||||||
private:
|
private:
|
||||||
|
|||||||
98
Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OpenGLFrameBuffer.h"
|
||||||
|
|
||||||
|
#include "glad/glad.h"
|
||||||
|
#include "Prism/Core/Log.h"
|
||||||
|
#include "Prism/Renderer/Renderer.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
OpenGLFrameBuffer::OpenGLFrameBuffer(const uint32_t width, const uint32_t height, const FramebufferFormat format)
|
||||||
|
: m_Width(width), m_Height(height), m_Format(format)
|
||||||
|
{
|
||||||
|
Resize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLFrameBuffer::~OpenGLFrameBuffer()
|
||||||
|
{
|
||||||
|
PM_RENDER_S({
|
||||||
|
glDeleteFramebuffers(1, &self->m_RendererID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLFrameBuffer::Bind() const
|
||||||
|
{
|
||||||
|
PM_RENDER_S({
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self->m_RendererID);
|
||||||
|
glViewport(0, 0, self->m_Width, self->m_Height);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLFrameBuffer::Unbind() const
|
||||||
|
{
|
||||||
|
PM_RENDER_S({
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLFrameBuffer::Resize(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
if (m_Width == width && m_Height == height)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_Width = width;
|
||||||
|
m_Height = height;
|
||||||
|
PM_RENDER_S({
|
||||||
|
if (self->m_RendererID)
|
||||||
|
{
|
||||||
|
glDeleteFramebuffers(1, &self->m_RendererID);
|
||||||
|
glDeleteTextures(1, &self->m_ColorAttachment);
|
||||||
|
glDeleteTextures(1, &self->m_DepthAttachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &self->m_RendererID);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, self->m_RendererID);
|
||||||
|
|
||||||
|
glGenTextures(1, &self->m_ColorAttachment);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, self->m_ColorAttachment);
|
||||||
|
|
||||||
|
// TODO: Create Hazel texture object based on format here
|
||||||
|
if (self->m_Format == FramebufferFormat::RGBA16F)
|
||||||
|
{
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, self->m_Width, self->m_Height, 0, GL_RGBA, GL_FLOAT, nullptr);
|
||||||
|
}
|
||||||
|
else if (self->m_Format == FramebufferFormat::RGBA8)
|
||||||
|
{
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->m_Width, self->m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
}
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->m_ColorAttachment, 0);
|
||||||
|
|
||||||
|
glGenTextures(1, &self->m_DepthAttachment);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, self->m_DepthAttachment);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, self->m_Width, self->m_Height, 0,
|
||||||
|
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, self->m_DepthAttachment, 0);
|
||||||
|
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
PM_CORE_ERROR("Framebuffer is incomplete!");
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLFrameBuffer::BindTexture(uint32_t slot) const
|
||||||
|
{
|
||||||
|
PM_RENDER_S1(slot, {
|
||||||
|
glActiveTexture(GL_TEXTURE0 + slot);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, self->m_ColorAttachment);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef OPENGLFRAMEBUFFER_H
|
||||||
|
#define OPENGLFRAMEBUFFER_H
|
||||||
|
#include "Prism/Renderer/FrameBuffer.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class OpenGLFrameBuffer : public FrameBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OpenGLFrameBuffer(uint32_t width, uint32_t height, FramebufferFormat format);
|
||||||
|
virtual ~OpenGLFrameBuffer();
|
||||||
|
|
||||||
|
void Bind() const override;
|
||||||
|
void Unbind() const override;
|
||||||
|
|
||||||
|
void Resize(uint32_t width, uint32_t height) override;
|
||||||
|
|
||||||
|
void BindTexture(uint32_t slot) const override;
|
||||||
|
|
||||||
|
RendererID GetRendererID() const override { return m_RendererID; }
|
||||||
|
RendererID GetColorAttachmentRendererID() const override { return m_ColorAttachment; }
|
||||||
|
RendererID GetDepthAttachmentRendererID() const override { return m_DepthAttachment; }
|
||||||
|
|
||||||
|
virtual uint32_t GetWidth() const { return m_Width; }
|
||||||
|
virtual uint32_t GetHeight() const { return m_Height; }
|
||||||
|
virtual FramebufferFormat GetFormat() const { return m_Format; }
|
||||||
|
private:
|
||||||
|
RendererID m_RendererID = 0;
|
||||||
|
uint32_t m_Width, m_Height;
|
||||||
|
FramebufferFormat m_Format;
|
||||||
|
|
||||||
|
RendererID m_ColorAttachment, m_DepthAttachment;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //OPENGLFRAMEBUFFER_H
|
||||||
@ -6,14 +6,42 @@
|
|||||||
#include "Prism/Renderer/RendererAPI.h"
|
#include "Prism/Renderer/RendererAPI.h"
|
||||||
|
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
|
#include "Prism/Core/Log.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
static void OpenGLLogMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
||||||
|
{
|
||||||
|
if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
|
||||||
|
PM_CORE_ERROR("{0}", message);
|
||||||
|
}
|
||||||
|
|
||||||
void RendererAPI::Init()
|
void RendererAPI::Init()
|
||||||
{
|
{
|
||||||
|
glDebugMessageCallback(OpenGLLogMessage, nullptr);
|
||||||
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
|
|
||||||
unsigned int vao;
|
unsigned int vao;
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
glBindVertexArray(vao);
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
//glEnable(GL_CULL_FACE);
|
||||||
|
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||||
|
glFrontFace(GL_CCW);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
auto& caps = GetCapabilities();
|
||||||
|
|
||||||
|
caps.Vendor = (const char*)glGetString(GL_VENDOR);
|
||||||
|
caps.Renderer = (const char*)glGetString(GL_RENDERER);
|
||||||
|
caps.Version = (const char*)glGetString(GL_VERSION);
|
||||||
|
|
||||||
|
glGetIntegerv(GL_MAX_SAMPLES, &caps.MaxSamples);
|
||||||
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &caps.MaxAnisotropy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererAPI::Shutdown()
|
void RendererAPI::Shutdown()
|
||||||
@ -31,8 +59,13 @@ namespace Prism
|
|||||||
glClearColor(r, g, b, a);
|
glClearColor(r, g, b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RendererAPI::DrawIndexed(const int count)
|
void RendererAPI::DrawIndexed(const unsigned int count, bool depthTest)
|
||||||
{
|
{
|
||||||
|
if (depthTest)
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
else
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
|
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,23 @@
|
|||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
OpenGLShader::OpenGLShader(const std::string& filepath)
|
OpenGLShader::OpenGLShader(const std::string& filepath)
|
||||||
|
: m_AssetPath(filepath)
|
||||||
{
|
{
|
||||||
ReadShaderFromFile(filepath);
|
size_t found = filepath.find_last_of("/\\");
|
||||||
CompileAndUploadShader();
|
m_Name = found != std::string::npos ? filepath.substr(found + 1) : filepath;
|
||||||
|
Reload();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::Reload()
|
||||||
|
{
|
||||||
|
ReadShaderFromFile(m_AssetPath);
|
||||||
|
PM_RENDER_S({
|
||||||
|
if (self->m_RendererID)
|
||||||
|
glDeleteShader(self->m_RendererID);
|
||||||
|
|
||||||
|
self->CompileAndUploadShader();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShader::Bind()
|
void OpenGLShader::Bind()
|
||||||
@ -37,6 +51,14 @@ namespace Prism
|
|||||||
self->UploadUniformFloat(name, value);
|
self->UploadUniformFloat(name, value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
case UniformType::Float3:
|
||||||
|
{
|
||||||
|
const std::string& name = decl.Name;
|
||||||
|
glm::vec3& values = *(glm::vec3*)(uniformBuffer.GetBuffer() + decl.Offset);
|
||||||
|
PM_RENDER_S2(name, values, {
|
||||||
|
self->UploadUniformFloat3(name, values);
|
||||||
|
});
|
||||||
|
}
|
||||||
case UniformType::Float4:
|
case UniformType::Float4:
|
||||||
{
|
{
|
||||||
const std::string& name = decl.Name;
|
const std::string& name = decl.Name;
|
||||||
@ -45,10 +67,38 @@ namespace Prism
|
|||||||
self->UploadUniformFloat4(name, values);
|
self->UploadUniformFloat4(name, values);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
case UniformType::Mat4:
|
||||||
|
{
|
||||||
|
const std::string& name = decl.Name;
|
||||||
|
glm::mat4& values = *(glm::mat4*)(uniformBuffer.GetBuffer() + decl.Offset);
|
||||||
|
PM_RENDER_S2(name, values, {
|
||||||
|
self->UploadUniformMat4(name, values);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::SetFloat(const std::string& name, float value)
|
||||||
|
{
|
||||||
|
PM_RENDER_S2(name, value, {
|
||||||
|
self->UploadUniformFloat(name, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::SetMat4(const std::string& name, const glm::mat4& value)
|
||||||
|
{
|
||||||
|
PM_RENDER_S2(name, value, {
|
||||||
|
self->UploadUniformMat4(name, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& OpenGLShader::GetName() const
|
||||||
|
{
|
||||||
|
return m_Name;
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLShader::ReadShaderFromFile(const std::string& filepath)
|
void OpenGLShader::ReadShaderFromFile(const std::string& filepath)
|
||||||
{
|
{
|
||||||
std::ifstream file(filepath, std::ios::in | std::ios::binary);
|
std::ifstream file(filepath, std::ios::in | std::ios::binary);
|
||||||
@ -71,6 +121,7 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
std::istringstream ss(m_ShaderSource);
|
std::istringstream ss(m_ShaderSource);
|
||||||
std::string token;
|
std::string token;
|
||||||
|
/*
|
||||||
while (ss >> token)
|
while (ss >> token)
|
||||||
{
|
{
|
||||||
if (token == "#type")
|
if (token == "#type")
|
||||||
@ -82,6 +133,7 @@ namespace Prism
|
|||||||
|
|
||||||
PM_CORE_TRACE("{}", token.c_str());
|
PM_CORE_TRACE("{}", token.c_str());
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
std::unordered_map<GLenum, std::string> shaderSources;
|
std::unordered_map<GLenum, std::string> shaderSources;
|
||||||
|
|
||||||
@ -119,7 +171,7 @@ namespace Prism
|
|||||||
const std::string& source = kv.second;
|
const std::string& source = kv.second;
|
||||||
GLuint shaderRendererID = glCreateShader(type);
|
GLuint shaderRendererID = glCreateShader(type);
|
||||||
const GLchar* sourcePtr = source.c_str();
|
const GLchar* sourcePtr = source.c_str();
|
||||||
glShaderSource(shaderRendererID, 1, &sourcePtr, NULL);
|
glShaderSource(shaderRendererID, 1, &sourcePtr, nullptr);
|
||||||
|
|
||||||
glCompileShader(shaderRendererID);
|
glCompileShader(shaderRendererID);
|
||||||
|
|
||||||
@ -167,6 +219,20 @@ namespace Prism
|
|||||||
glDetachShader(program, id);
|
glDetachShader(program, id);
|
||||||
|
|
||||||
m_RendererID = program;
|
m_RendererID = program;
|
||||||
|
|
||||||
|
// Bind default texture unit
|
||||||
|
UploadUniformInt("u_Texture", 0);
|
||||||
|
|
||||||
|
// PBR shader textures
|
||||||
|
UploadUniformInt("u_AlbedoTexture", 1);
|
||||||
|
UploadUniformInt("u_NormalTexture", 2);
|
||||||
|
UploadUniformInt("u_MetalnessTexture", 3);
|
||||||
|
UploadUniformInt("u_RoughnessTexture", 4);
|
||||||
|
|
||||||
|
UploadUniformInt("u_EnvRadianceTex", 10);
|
||||||
|
UploadUniformInt("u_EnvIrradianceTex", 11);
|
||||||
|
|
||||||
|
UploadUniformInt("u_BRDFLUTTexture", 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLenum OpenGLShader::ShaderTypeFromString(const std::string& type)
|
GLenum OpenGLShader::ShaderTypeFromString(const std::string& type)
|
||||||
@ -179,15 +245,63 @@ namespace Prism
|
|||||||
return GL_NONE;
|
return GL_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShader::UploadUniformFloat(const std::string& name, float value)
|
void OpenGLShader::UploadUniformInt(const std::string& name, const int value) const
|
||||||
{
|
{
|
||||||
glUseProgram(m_RendererID);
|
glUseProgram(m_RendererID);
|
||||||
glUniform1f(glGetUniformLocation(m_RendererID, name.c_str()), value);
|
auto location = glGetUniformLocation(m_RendererID, name.c_str());
|
||||||
|
if (location != -1)
|
||||||
|
glUniform1i(location, value);
|
||||||
|
else
|
||||||
|
PM_CORE_WARN("Uniform '{0}' not found!", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& values)
|
void OpenGLShader::UploadUniformFloat(const std::string& name, const float value) const
|
||||||
{
|
{
|
||||||
glUseProgram(m_RendererID);
|
glUseProgram(m_RendererID);
|
||||||
glUniform4f(glGetUniformLocation(m_RendererID, name.c_str()), values.x, values.y, values.z, values.w);
|
auto location = glGetUniformLocation(m_RendererID, name.c_str());
|
||||||
|
if (location != -1)
|
||||||
|
glUniform1f(location, value);
|
||||||
|
else
|
||||||
|
PM_CORE_WARN("Uniform '{0}' not found!", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformFloat2(const std::string& name, const glm::vec2& values) const
|
||||||
|
{
|
||||||
|
glUseProgram(m_RendererID);
|
||||||
|
auto location = glGetUniformLocation(m_RendererID, name.c_str());
|
||||||
|
if (location != -1)
|
||||||
|
glUniform2fv(location,1, glm::value_ptr(values));
|
||||||
|
else
|
||||||
|
PM_CORE_WARN("Uniform '{0}' not found!", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformFloat3(const std::string& name, const glm::vec3& values) const
|
||||||
|
{
|
||||||
|
glUseProgram(m_RendererID);
|
||||||
|
auto location = glGetUniformLocation(m_RendererID, name.c_str());
|
||||||
|
if (location != -1)
|
||||||
|
glUniform3fv(location,1, glm::value_ptr(values));
|
||||||
|
else
|
||||||
|
PM_CORE_WARN("Uniform '{0}' not found!", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& values) const
|
||||||
|
{
|
||||||
|
glUseProgram(m_RendererID);
|
||||||
|
auto location = glGetUniformLocation(m_RendererID, name.c_str());
|
||||||
|
if (location != -1)
|
||||||
|
glUniform4fv(location,1, glm::value_ptr(values));
|
||||||
|
else
|
||||||
|
PM_CORE_WARN("Uniform '{0}' not found!", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformMat4(const std::string& name, const glm::mat4& values) const
|
||||||
|
{
|
||||||
|
glUseProgram(m_RendererID);
|
||||||
|
auto location = glGetUniformLocation(m_RendererID, name.c_str());
|
||||||
|
if (location != -1)
|
||||||
|
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(values));
|
||||||
|
else
|
||||||
|
PM_CORE_WARN("Uniform '{0}' not found!", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,22 +16,32 @@ namespace Prism
|
|||||||
public:
|
public:
|
||||||
OpenGLShader(const std::string& filepath);
|
OpenGLShader(const std::string& filepath);
|
||||||
|
|
||||||
|
virtual void Reload();
|
||||||
virtual void Bind() override;
|
virtual void Bind() override;
|
||||||
|
|
||||||
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) override;
|
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) override;
|
||||||
|
|
||||||
|
virtual void SetFloat(const std::string& name, float value) override;
|
||||||
|
virtual void SetMat4(const std::string& name, const glm::mat4& value) override;
|
||||||
|
const std::string& GetName() const override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ReadShaderFromFile(const std::string& filepath);
|
void ReadShaderFromFile(const std::string& filepath);
|
||||||
void CompileAndUploadShader();
|
void CompileAndUploadShader();
|
||||||
|
|
||||||
static GLenum ShaderTypeFromString(const std::string& type);
|
static GLenum ShaderTypeFromString(const std::string& type);
|
||||||
|
|
||||||
void UploadUniformFloat(const std::string& name, float value);
|
void UploadUniformInt(const std::string& name, int value) const;
|
||||||
void UploadUniformFloat2(const std::string& name, float* values);
|
void UploadUniformFloat(const std::string& name, float value) const;
|
||||||
void UploadUniformFloat3(const std::string& name, float* values);
|
void UploadUniformFloat2(const std::string& name, const glm::vec2& values) const;
|
||||||
void UploadUniformFloat4(const std::string& name, const glm::vec4& values);
|
void UploadUniformFloat3(const std::string& name, const glm::vec3& values) const;
|
||||||
|
void UploadUniformFloat4(const std::string& name, const glm::vec4& values) const;
|
||||||
|
void UploadUniformMat4(const std::string& name, const glm::mat4& values) const;
|
||||||
private:
|
private:
|
||||||
RendererID m_RendererID;
|
RendererID m_RendererID;
|
||||||
|
|
||||||
|
std::string m_Name, m_AssetPath;
|
||||||
std::string m_ShaderSource;
|
std::string m_ShaderSource;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
#include "OpenGLTexture.h"
|
#include "OpenGLTexture.h"
|
||||||
|
|
||||||
#include "glad/glad.h"
|
|
||||||
#include "Prism/Renderer/Renderer.h"
|
#include "Prism/Renderer/Renderer.h"
|
||||||
|
#include "glad/glad.h"
|
||||||
|
#include "stb_image.h"
|
||||||
|
#include "Prism/Core/Log.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -13,12 +15,23 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
{
|
{
|
||||||
case Prism::TextureFormat::RGB: return GL_RGB;
|
case TextureFormat::RGB: return GL_RGB;
|
||||||
case Prism::TextureFormat::RGBA: return GL_RGBA;
|
case TextureFormat::RGBA: return GL_RGBA;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static int CalculateMipMapCount(const int width, const int height)
|
||||||
|
{
|
||||||
|
int levels = 1;
|
||||||
|
while ((width | height) >> levels) {
|
||||||
|
levels++;
|
||||||
|
}
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******************************************
|
||||||
|
// Texture2D
|
||||||
|
// ******************************************
|
||||||
|
|
||||||
OpenGLTexture2D::OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height)
|
OpenGLTexture2D::OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height)
|
||||||
: m_Format(format), m_Width(width), m_Height(height)
|
: m_Format(format), m_Width(width), m_Height(height)
|
||||||
@ -27,13 +40,186 @@ namespace Prism
|
|||||||
PM_RENDER_1(self, {
|
PM_RENDER_1(self, {
|
||||||
glGenTextures(1, &self->m_RendererID);
|
glGenTextures(1, &self->m_RendererID);
|
||||||
glBindTexture(GL_TEXTURE_2D, self->m_RendererID);
|
glBindTexture(GL_TEXTURE_2D, self->m_RendererID);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTextureParameterf(self->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(self->m_Format), self->m_Width, self->m_Height, 0, PrismToOpenGLTextureFormat(self->m_Format), GL_UNSIGNED_BYTE, nullptr);
|
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(self->m_Format), self->m_Width, self->m_Height, 0, PrismToOpenGLTextureFormat(self->m_Format), GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb)
|
||||||
|
: m_FilePath(path)
|
||||||
|
{
|
||||||
|
int width, height, channels;
|
||||||
|
PM_CORE_INFO("Loading texture {0}, srgb={1}", path, srgb);
|
||||||
|
m_ImageData = stbi_load(path.c_str(), &width, &height, &channels, srgb ? STBI_rgb : STBI_rgb_alpha);
|
||||||
|
|
||||||
|
m_Width = width;
|
||||||
|
m_Height = height;
|
||||||
|
m_Format = TextureFormat::RGBA;
|
||||||
|
|
||||||
|
PM_RENDER_S1(srgb, {
|
||||||
|
// TODO: Consolidate properly
|
||||||
|
if (srgb)
|
||||||
|
{
|
||||||
|
glCreateTextures(GL_TEXTURE_2D, 1, &self->m_RendererID);
|
||||||
|
int levels = CalculateMipMapCount(self->m_Width, self->m_Height);
|
||||||
|
PM_CORE_INFO("Creating srgb texture width {0} mips", levels);
|
||||||
|
glTextureStorage2D(self->m_RendererID, levels, GL_SRGB8, self->m_Width, self->m_Height);
|
||||||
|
glTextureParameteri(self->m_RendererID, GL_TEXTURE_MIN_FILTER, levels > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||||
|
glTextureParameteri(self->m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glTextureSubImage2D(self->m_RendererID, 0, 0, 0, self->m_Width, self->m_Height, GL_RGB, GL_UNSIGNED_BYTE, self->m_ImageData);
|
||||||
|
glGenerateTextureMipmap(self->m_RendererID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glGenTextures(1, &self->m_RendererID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, self->m_RendererID);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(self->m_Format), self->m_Width, self->m_Height, 0, srgb ? GL_SRGB8 : PrismToOpenGLTextureFormat(self->m_Format), GL_UNSIGNED_BYTE, self->m_ImageData);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
stbi_image_free(self->m_ImageData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
OpenGLTexture2D::~OpenGLTexture2D()
|
OpenGLTexture2D::~OpenGLTexture2D()
|
||||||
{
|
{
|
||||||
|
auto self = this;
|
||||||
|
PM_RENDER_1(self, {
|
||||||
|
glDeleteTextures(1, &self->m_RendererID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTexture2D::Bind(unsigned int slot) const
|
||||||
|
{
|
||||||
|
PM_RENDER_S1(slot, {
|
||||||
|
glBindTextureUnit(slot, self->m_RendererID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ******************************************
|
||||||
|
// TextureCube
|
||||||
|
// ******************************************
|
||||||
|
|
||||||
|
OpenGLTextureCube::OpenGLTextureCube(const std::string& path)
|
||||||
|
: m_FilePath(path)
|
||||||
|
{
|
||||||
|
int width, height, channels;
|
||||||
|
stbi_set_flip_vertically_on_load(false);
|
||||||
|
m_ImageData = stbi_load(path.c_str(), &width, &height, &channels, STBI_rgb);
|
||||||
|
|
||||||
|
m_Width = width;
|
||||||
|
m_Height = height;
|
||||||
|
m_Format = TextureFormat::RGB;
|
||||||
|
|
||||||
|
unsigned int faceWidth = m_Width / 4;
|
||||||
|
unsigned int faceHeight = m_Height / 3;
|
||||||
|
PM_CORE_ASSERT(faceWidth == faceHeight, "Non-square faces!");
|
||||||
|
|
||||||
|
std::array<unsigned char*, 6> faces;
|
||||||
|
for (size_t i = 0; i < faces.size(); i++)
|
||||||
|
faces[i] = new unsigned char[faceWidth * faceHeight * 3]; // 3 BPP
|
||||||
|
|
||||||
|
int faceIndex = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
for (size_t y = 0; y < faceHeight; y++)
|
||||||
|
{
|
||||||
|
size_t yOffset = y + faceHeight;
|
||||||
|
for (size_t x = 0; x < faceWidth; x++)
|
||||||
|
{
|
||||||
|
size_t xOffset = x + i * faceWidth;
|
||||||
|
faces[faceIndex][(x + y * faceWidth) * 3 + 0] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 0];
|
||||||
|
faces[faceIndex][(x + y * faceWidth) * 3 + 1] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 1];
|
||||||
|
faces[faceIndex][(x + y * faceWidth) * 3 + 2] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
faceIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
// Skip the middle one
|
||||||
|
if (i == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (size_t y = 0; y < faceHeight; y++)
|
||||||
|
{
|
||||||
|
size_t yOffset = y + i * faceHeight;
|
||||||
|
for (size_t x = 0; x < faceWidth; x++)
|
||||||
|
{
|
||||||
|
size_t xOffset = x + faceWidth;
|
||||||
|
faces[faceIndex][(x + y * faceWidth) * 3 + 0] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 0];
|
||||||
|
faces[faceIndex][(x + y * faceWidth) * 3 + 1] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 1];
|
||||||
|
faces[faceIndex][(x + y * faceWidth) * 3 + 2] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
faceIndex++;
|
||||||
|
}
|
||||||
|
PM_RENDER_S3(faces, faceWidth, faceHeight, {
|
||||||
|
glGenTextures(1, &self->m_RendererID);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, self->m_RendererID);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTextureParameterf(self->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
|
||||||
|
|
||||||
|
auto format = PrismToOpenGLTextureFormat(self->m_Format);
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[2]);
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[0]);
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[4]);
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[5]);
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[1]);
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[3]);
|
||||||
|
|
||||||
|
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < faces.size(); i++)
|
||||||
|
delete[] faces[i];
|
||||||
|
|
||||||
|
stbi_image_free(self->m_ImageData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLTextureCube::~OpenGLTextureCube()
|
||||||
|
{
|
||||||
|
auto self = this;
|
||||||
|
PM_RENDER_1(self, {
|
||||||
|
glDeleteTextures(1, &self->m_RendererID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTextureCube::Bind(unsigned int slot) const
|
||||||
|
{
|
||||||
|
PM_RENDER_S1(slot, {
|
||||||
|
glActiveTexture(GL_TEXTURE0 + slot);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, self->m_RendererID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -14,15 +14,52 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height);
|
OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height);
|
||||||
~OpenGLTexture2D();
|
OpenGLTexture2D(const std::string& path, bool srgb);
|
||||||
|
virtual ~OpenGLTexture2D();
|
||||||
|
|
||||||
|
virtual void Bind(unsigned int slot = 0) const override;
|
||||||
|
|
||||||
virtual TextureFormat GetFormat() const { return m_Format; }
|
virtual TextureFormat GetFormat() const { return m_Format; }
|
||||||
virtual unsigned int GetWidth() const { return m_Width; }
|
virtual unsigned int GetWidth() const { return m_Width; }
|
||||||
virtual unsigned int GetHeight() const { return m_Height; }
|
virtual unsigned int GetHeight() const { return m_Height; }
|
||||||
|
|
||||||
|
virtual const std::string& GetPath() const override { return m_FilePath; }
|
||||||
|
|
||||||
|
virtual RendererID GetRendererID() const override { return m_RendererID; }
|
||||||
private:
|
private:
|
||||||
RendererID m_RendererID;
|
RendererID m_RendererID;
|
||||||
TextureFormat m_Format;
|
TextureFormat m_Format;
|
||||||
unsigned int m_Width, m_Height;
|
unsigned int m_Width, m_Height;
|
||||||
|
|
||||||
|
unsigned char* m_ImageData;
|
||||||
|
|
||||||
|
std::string m_FilePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenGLTextureCube : public TextureCube
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OpenGLTextureCube(const std::string& path);
|
||||||
|
virtual ~OpenGLTextureCube();
|
||||||
|
|
||||||
|
virtual void Bind(unsigned int slot = 0) const override;
|
||||||
|
|
||||||
|
virtual TextureFormat GetFormat() const override { return m_Format; }
|
||||||
|
virtual unsigned int GetWidth() const override { return m_Width; }
|
||||||
|
virtual unsigned int GetHeight() const override { return m_Height; }
|
||||||
|
|
||||||
|
virtual const std::string& GetPath() const override { return m_FilePath; }
|
||||||
|
|
||||||
|
virtual RendererID GetRendererID() const override { return m_RendererID; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RendererID m_RendererID;
|
||||||
|
TextureFormat m_Format;
|
||||||
|
unsigned int m_Width, m_Height;
|
||||||
|
|
||||||
|
unsigned char* m_ImageData;
|
||||||
|
|
||||||
|
std::string m_FilePath;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
Input* Input::s_Instance = new WindowsInput;
|
||||||
|
|
||||||
bool WindowsInput::IsKeyPressedImpl(const int keycode)
|
bool WindowsInput::IsKeyPressedImpl(const int keycode)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -71,8 +71,8 @@ namespace Prism
|
|||||||
int success = glfwInit();
|
int success = glfwInit();
|
||||||
PM_CORE_ASSERT(success, "Could not initialize GLFW!");
|
PM_CORE_ASSERT(success, "Could not initialize GLFW!");
|
||||||
glfwSetErrorCallback(GLFWErrorCallback);
|
glfwSetErrorCallback(GLFWErrorCallback);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
|
||||||
s_GLFWInitialized = true;
|
s_GLFWInitialized = true;
|
||||||
|
|||||||
@ -32,6 +32,7 @@ namespace Prism
|
|||||||
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0) = 0;
|
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0) = 0;
|
||||||
virtual void Bind() const = 0;
|
virtual void Bind() const = 0;
|
||||||
|
|
||||||
|
virtual uint32_t GetCount() const = 0;
|
||||||
virtual unsigned int GetSize() const = 0;
|
virtual unsigned int GetSize() const = 0;
|
||||||
virtual RendererID GetRendererID() const = 0;
|
virtual RendererID GetRendererID() const = 0;
|
||||||
|
|
||||||
|
|||||||
111
Prism/src/Prism/Renderer/Camera.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Camera.h"
|
||||||
|
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "glm/detail/type_quat.hpp"
|
||||||
|
|
||||||
|
#include "glm/gtc/quaternion.hpp"
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include "glm/gtx/quaternion.hpp"
|
||||||
|
#include "Prism/Core/Input.h"
|
||||||
|
|
||||||
|
#define M_PI 3.14159f
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
Camera::Camera(const glm::mat4& projectionMatrix)
|
||||||
|
: m_ProjectionMatrix(projectionMatrix)
|
||||||
|
{
|
||||||
|
// Sensible defaults
|
||||||
|
m_PanSpeed = 0.0015f;
|
||||||
|
m_RotationSpeed = 0.002f;
|
||||||
|
m_ZoomSpeed = 0.2f;
|
||||||
|
|
||||||
|
m_Position = { 0, 0, 10 };
|
||||||
|
m_Rotation = glm::vec3(90.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
m_FocalPoint = glm::vec3(0.0f);
|
||||||
|
m_Distance = glm::distance(m_Position, m_FocalPoint);
|
||||||
|
|
||||||
|
m_Yaw = 3.0f * (float)M_PI / 4.0f;
|
||||||
|
m_Pitch = M_PI / 4.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::Focus()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::Update()
|
||||||
|
{
|
||||||
|
if (Input::IsKeyPressed(GLFW_KEY_LEFT_ALT))
|
||||||
|
{
|
||||||
|
const glm::vec2& mouse{ Input::GetMouseX(), Input::GetMouseY() };
|
||||||
|
glm::vec2 delta = mouse - m_InitialMousePosition;
|
||||||
|
m_InitialMousePosition = mouse;
|
||||||
|
|
||||||
|
if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_MIDDLE))
|
||||||
|
MousePan(delta);
|
||||||
|
else if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_LEFT))
|
||||||
|
MouseRotate(delta);
|
||||||
|
else if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_RIGHT))
|
||||||
|
MouseZoom(delta.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Position = CalculatePosition();
|
||||||
|
|
||||||
|
glm::quat orientation = GetOrientation();
|
||||||
|
m_Rotation = glm::eulerAngles(orientation) * (180.0f / (float)M_PI);
|
||||||
|
m_ViewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 1)) * glm::toMat4(glm::conjugate(orientation)) * glm::translate(glm::mat4(1.0f), -m_Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 Camera::GetUpDirection()
|
||||||
|
{
|
||||||
|
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 Camera::GetRightDirection()
|
||||||
|
{
|
||||||
|
return glm::rotate(GetOrientation(), glm::vec3(1.0f, 0.0f, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 Camera::GetForwardDirection()
|
||||||
|
{
|
||||||
|
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 0.0f, -1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::MousePan(const glm::vec2& delta)
|
||||||
|
{
|
||||||
|
m_FocalPoint += -GetRightDirection() * delta.x * m_PanSpeed * m_Distance;
|
||||||
|
m_FocalPoint += GetUpDirection() * delta.y * m_PanSpeed * m_Distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::MouseRotate(const glm::vec2& delta)
|
||||||
|
{
|
||||||
|
float yawSign = GetUpDirection().y < 0 ? -1.0f : 1.0f;
|
||||||
|
m_Yaw += yawSign * delta.x * m_RotationSpeed;
|
||||||
|
m_Pitch += delta.y * m_RotationSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::MouseZoom(float delta)
|
||||||
|
{
|
||||||
|
m_Distance -= delta * m_ZoomSpeed;
|
||||||
|
if (m_Distance < 1.0f)
|
||||||
|
{
|
||||||
|
m_FocalPoint += GetForwardDirection();
|
||||||
|
m_Distance = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 Camera::CalculatePosition()
|
||||||
|
{
|
||||||
|
return m_FocalPoint - GetForwardDirection() * m_Distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat Camera::GetOrientation()
|
||||||
|
{
|
||||||
|
return glm::quat(glm::vec3(-m_Pitch, -m_Yaw, 0.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
55
Prism/src/Prism/Renderer/Camera.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef CAMERA_H
|
||||||
|
#define CAMERA_H
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class Camera
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Camera(const glm::mat4& projectionMatrix);
|
||||||
|
|
||||||
|
void Focus();
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
inline float GetDistance() const { return m_Distance; }
|
||||||
|
inline void SetDistance(float distance) { m_Distance = distance; }
|
||||||
|
|
||||||
|
inline void SetProjectionMatrix(const glm::mat4& projectionMatrix) { m_ProjectionMatrix = projectionMatrix; }
|
||||||
|
|
||||||
|
const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; }
|
||||||
|
const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; }
|
||||||
|
|
||||||
|
glm::vec3 GetUpDirection();
|
||||||
|
glm::vec3 GetRightDirection();
|
||||||
|
glm::vec3 GetForwardDirection();
|
||||||
|
const glm::vec3& GetPosition() const { return m_Position; }
|
||||||
|
private:
|
||||||
|
void MousePan(const glm::vec2& delta);
|
||||||
|
void MouseRotate(const glm::vec2& delta);
|
||||||
|
void MouseZoom(float delta);
|
||||||
|
|
||||||
|
glm::vec3 CalculatePosition();
|
||||||
|
glm::quat GetOrientation();
|
||||||
|
private:
|
||||||
|
glm::mat4 m_ProjectionMatrix, m_ViewMatrix;
|
||||||
|
glm::vec3 m_Position, m_Rotation, m_FocalPoint;
|
||||||
|
|
||||||
|
bool m_Panning, m_Rotating;
|
||||||
|
glm::vec2 m_InitialMousePosition;
|
||||||
|
glm::vec3 m_InitialFocalPoint, m_InitialRotation;
|
||||||
|
|
||||||
|
float m_Distance;
|
||||||
|
float m_PanSpeed, m_RotationSpeed, m_ZoomSpeed;
|
||||||
|
|
||||||
|
float m_Pitch, m_Yaw;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //CAMERA_H
|
||||||
46
Prism/src/Prism/Renderer/FrameBuffer.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "FrameBuffer.h"
|
||||||
|
|
||||||
|
#include "Prism/Platform/OpenGL/OpenGLFrameBuffer.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
FrameBuffer* Prism::FrameBuffer::Create(uint32_t width, uint32_t height, FramebufferFormat format)
|
||||||
|
{
|
||||||
|
FrameBuffer* result = nullptr;
|
||||||
|
switch (RendererAPI::Current())
|
||||||
|
{
|
||||||
|
case RendererAPIType::None: return nullptr;
|
||||||
|
case RendererAPIType::OpenGL: result = new OpenGLFrameBuffer(width, height, format);
|
||||||
|
}
|
||||||
|
FrameBufferPool::GetGlobal()->Add(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameBufferPool* FrameBufferPool::s_Instance = new FrameBufferPool;
|
||||||
|
|
||||||
|
|
||||||
|
FrameBufferPool::FrameBufferPool(uint32_t maxFBs)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameBufferPool::~FrameBufferPool()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<FrameBuffer> FrameBufferPool::AllocateBuffer()
|
||||||
|
{
|
||||||
|
// m_Pool.push_back();
|
||||||
|
return std::weak_ptr<FrameBuffer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameBufferPool::Add(FrameBuffer* framebuffer)
|
||||||
|
{
|
||||||
|
m_Pool.push_back(framebuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
57
Prism/src/Prism/Renderer/FrameBuffer.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef FRAMEBUFFER_H
|
||||||
|
#define FRAMEBUFFER_H
|
||||||
|
#include "RendererAPI.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
enum class FramebufferFormat
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
RGBA8 = 1,
|
||||||
|
RGBA16F = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrameBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static FrameBuffer* Create(uint32_t width, uint32_t height, FramebufferFormat format);
|
||||||
|
|
||||||
|
virtual ~FrameBuffer() {}
|
||||||
|
virtual void Bind() const = 0;
|
||||||
|
virtual void Unbind() const = 0;
|
||||||
|
|
||||||
|
virtual void Resize(uint32_t width, uint32_t height) = 0;
|
||||||
|
|
||||||
|
virtual void BindTexture(uint32_t slot = 0) const = 0;
|
||||||
|
|
||||||
|
virtual RendererID GetRendererID() const = 0;
|
||||||
|
virtual RendererID GetColorAttachmentRendererID() const = 0;
|
||||||
|
virtual RendererID GetDepthAttachmentRendererID() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FrameBufferPool final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FrameBufferPool(uint32_t maxFBs = 32);
|
||||||
|
~FrameBufferPool();
|
||||||
|
|
||||||
|
std::weak_ptr<FrameBuffer> AllocateBuffer();
|
||||||
|
void Add(FrameBuffer* framebuffer);
|
||||||
|
|
||||||
|
const std::vector<FrameBuffer*>& GetAll() const { return m_Pool; }
|
||||||
|
|
||||||
|
inline static FrameBufferPool* GetGlobal() { return s_Instance; }
|
||||||
|
private:
|
||||||
|
std::vector<FrameBuffer*> m_Pool;
|
||||||
|
|
||||||
|
static FrameBufferPool* s_Instance;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //FRAMEBUFFER_H
|
||||||
129
Prism/src/Prism/Renderer/Mesh.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Mesh.h"
|
||||||
|
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "assimp/DefaultLogger.hpp"
|
||||||
|
#include "assimp/Importer.hpp"
|
||||||
|
#include "assimp/LogStream.hpp"
|
||||||
|
#include "assimp/postprocess.h"
|
||||||
|
#include "assimp/scene.h"
|
||||||
|
#include "glad/glad.h"
|
||||||
|
#include "Prism/Core/Log.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const unsigned int ImportFlags =
|
||||||
|
aiProcess_CalcTangentSpace |
|
||||||
|
aiProcess_Triangulate |
|
||||||
|
aiProcess_SortByPType |
|
||||||
|
aiProcess_PreTransformVertices |
|
||||||
|
aiProcess_GenNormals |
|
||||||
|
aiProcess_GenUVCoords |
|
||||||
|
aiProcess_OptimizeMeshes |
|
||||||
|
aiProcess_Debone |
|
||||||
|
aiProcess_ValidateDataStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LogStream : public Assimp::LogStream
|
||||||
|
{
|
||||||
|
static void Initialize()
|
||||||
|
{
|
||||||
|
if (Assimp::DefaultLogger::isNullLogger())
|
||||||
|
{
|
||||||
|
Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
|
||||||
|
Assimp::DefaultLogger::get()->attachStream(new LogStream, Assimp::Logger::Err | Assimp::Logger::Warn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(const char* message) override
|
||||||
|
{
|
||||||
|
PM_CORE_ERROR("Assimp error: {0}", message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Mesh::Mesh(const std::string& filename)
|
||||||
|
: m_FilePath(filename)
|
||||||
|
{
|
||||||
|
LogStream::Initialize();
|
||||||
|
|
||||||
|
PM_CORE_INFO("Loading mesh: {0}", filename.c_str());
|
||||||
|
|
||||||
|
Assimp::Importer importer;
|
||||||
|
|
||||||
|
const aiScene* scene = importer.ReadFile(filename, ImportFlags);
|
||||||
|
if (!scene || !scene->HasMeshes())
|
||||||
|
PM_CORE_ERROR("Failed to load mesh file: {0}", filename);
|
||||||
|
|
||||||
|
aiMesh* mesh = scene->mMeshes[0];
|
||||||
|
|
||||||
|
PM_CORE_ASSERT(mesh->HasPositions(), "Meshes require positions.");
|
||||||
|
PM_CORE_ASSERT(mesh->HasNormals(), "Meshes require normals.");
|
||||||
|
|
||||||
|
m_Vertices.reserve(mesh->mNumVertices);
|
||||||
|
|
||||||
|
// Extract vertices from model
|
||||||
|
for (size_t i = 0; i < m_Vertices.capacity(); i++)
|
||||||
|
{
|
||||||
|
Vertex vertex;
|
||||||
|
vertex.Position = { mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z };
|
||||||
|
vertex.Normal = { mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z };
|
||||||
|
|
||||||
|
if (mesh->HasTangentsAndBitangents())
|
||||||
|
{
|
||||||
|
vertex.Tangent = { mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z };
|
||||||
|
vertex.Binormal = { mesh->mBitangents[i].x, mesh->mBitangents[i].y, mesh->mBitangents[i].z };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh->HasTextureCoords(0))
|
||||||
|
vertex.Texcoord = { mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y };
|
||||||
|
m_Vertices.push_back(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_VertexBuffer.reset(VertexBuffer::Create());
|
||||||
|
m_VertexBuffer->SetData(m_Vertices.data(), m_Vertices.size() * sizeof(Vertex));
|
||||||
|
|
||||||
|
// Extract indices from model
|
||||||
|
m_Indices.reserve(mesh->mNumFaces);
|
||||||
|
for (size_t i = 0; i < m_Indices.capacity(); i++)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(mesh->mFaces[i].mNumIndices == 3, "Must have 3 indices.");
|
||||||
|
m_Indices.push_back({ mesh->mFaces[i].mIndices[0], mesh->mFaces[i].mIndices[1], mesh->mFaces[i].mIndices[2] });
|
||||||
|
}
|
||||||
|
|
||||||
|
m_IndexBuffer.reset(IndexBuffer::Create());
|
||||||
|
m_IndexBuffer->SetData(m_Indices.data(), m_Indices.size() * sizeof(Index));
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh::~Mesh()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::Render()
|
||||||
|
{
|
||||||
|
// TODO: Sort this out
|
||||||
|
m_VertexBuffer->Bind();
|
||||||
|
m_IndexBuffer->Bind();
|
||||||
|
PM_RENDER_S({
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Position));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Normal));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Tangent));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(3);
|
||||||
|
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Binormal));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(4);
|
||||||
|
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Texcoord));
|
||||||
|
});
|
||||||
|
Renderer::DrawIndexed(m_IndexBuffer->GetCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
52
Prism/src/Prism/Renderer/Mesh.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef MESH_H
|
||||||
|
#define MESH_H
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "Buffer.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class Mesh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
glm::vec3 Position;
|
||||||
|
glm::vec3 Normal;
|
||||||
|
glm::vec3 Tangent;
|
||||||
|
glm::vec3 Binormal;
|
||||||
|
glm::vec2 Texcoord;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Vertex) == 14 * sizeof(float));
|
||||||
|
static const int NumAttributes = 5;
|
||||||
|
|
||||||
|
struct Index
|
||||||
|
{
|
||||||
|
uint32_t V1, V2, V3;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Index) == 3 * sizeof(uint32_t));
|
||||||
|
|
||||||
|
Mesh(const std::string& filename);
|
||||||
|
~Mesh();
|
||||||
|
|
||||||
|
void Render();
|
||||||
|
|
||||||
|
inline const std::string& GetFilePath() const { return m_FilePath; }
|
||||||
|
private:
|
||||||
|
std::vector<Vertex> m_Vertices;
|
||||||
|
std::vector<Index> m_Indices;
|
||||||
|
|
||||||
|
std::unique_ptr<VertexBuffer> m_VertexBuffer;
|
||||||
|
std::unique_ptr<IndexBuffer> m_IndexBuffer;
|
||||||
|
|
||||||
|
std::string m_FilePath;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //MESH_H
|
||||||
@ -27,10 +27,10 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::DrawIndexed(const int count)
|
void Renderer::DrawIndexed(unsigned int count, bool depthTest)
|
||||||
{
|
{
|
||||||
PM_RENDER_1(count, {
|
PM_RENDER_2(count, depthTest, {
|
||||||
RendererAPI::DrawIndexed(count);
|
RendererAPI::DrawIndexed(count, depthTest);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace Prism
|
|||||||
static void Clear();
|
static void Clear();
|
||||||
static void Clear(float r, float g, float b, float a = 1.0f);
|
static void Clear(float r, float g, float b, float a = 1.0f);
|
||||||
static void SetClearColor(float r, float g, float b, float a);
|
static void SetClearColor(float r, float g, float b, float a);
|
||||||
static void DrawIndexed(const int count);
|
static void DrawIndexed(unsigned int count, bool depthTest = true);
|
||||||
|
|
||||||
// test
|
// test
|
||||||
static void ClearMagenta();
|
static void ClearMagenta();
|
||||||
|
|||||||
@ -16,7 +16,17 @@ namespace Prism
|
|||||||
OpenGL
|
OpenGL
|
||||||
};
|
};
|
||||||
|
|
||||||
class PRISM_API RendererAPI
|
struct RenderAPICapabilities
|
||||||
|
{
|
||||||
|
std::string Vendor;
|
||||||
|
std::string Renderer;
|
||||||
|
std::string Version;
|
||||||
|
|
||||||
|
int MaxSamples;
|
||||||
|
float MaxAnisotropy;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RendererAPI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Init();
|
static void Init();
|
||||||
@ -25,9 +35,15 @@ namespace Prism
|
|||||||
static void Clear(float r, float g, float b, float a);
|
static void Clear(float r, float g, float b, float a);
|
||||||
static void SetClearColor(float r, float g, float b, float a);
|
static void SetClearColor(float r, float g, float b, float a);
|
||||||
|
|
||||||
static void DrawIndexed(int count);
|
static void DrawIndexed(unsigned int count, bool depthTest = true);
|
||||||
static RendererAPIType Current() { return s_CurrentRendererAPI; }
|
static RendererAPIType Current() { return s_CurrentRendererAPI; }
|
||||||
|
|
||||||
|
static RenderAPICapabilities& GetCapabilities()
|
||||||
|
{
|
||||||
|
static RenderAPICapabilities capabilities;
|
||||||
|
return capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static RendererAPIType s_CurrentRendererAPI;
|
static RendererAPIType s_CurrentRendererAPI;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,13 +9,20 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
std::vector<Shader*> Shader::s_AllShaders;
|
||||||
|
|
||||||
Shader* Shader::Create(const std::string& filepath)
|
Shader* Shader::Create(const std::string& filepath)
|
||||||
{
|
{
|
||||||
|
Shader* result = nullptr;
|
||||||
|
|
||||||
switch (RendererAPI::Current())
|
switch (RendererAPI::Current())
|
||||||
{
|
{
|
||||||
case RendererAPIType::None: return nullptr;
|
case RendererAPIType::None: return nullptr;
|
||||||
case RendererAPIType::OpenGL: return new OpenGLShader(filepath);
|
case RendererAPIType::OpenGL: result = new OpenGLShader(filepath);
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
|
s_AllShaders.push_back(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,6 +53,7 @@ namespace Prism
|
|||||||
byte Buffer[N];
|
byte Buffer[N];
|
||||||
UniformDecl Uniforms[U];
|
UniformDecl Uniforms[U];
|
||||||
std::ptrdiff_t Cursor = 0;
|
std::ptrdiff_t Cursor = 0;
|
||||||
|
int Index = 0;
|
||||||
|
|
||||||
virtual const byte* GetBuffer() const override { return Buffer; }
|
virtual const byte* GetBuffer() const override { return Buffer; }
|
||||||
virtual const UniformDecl* GetUniforms() const override { return Uniforms; }
|
virtual const UniformDecl* GetUniforms() const override { return Uniforms; }
|
||||||
@ -63,27 +64,48 @@ namespace Prism
|
|||||||
|
|
||||||
void Push(const std::string& name, const float& data)
|
void Push(const std::string& name, const float& data)
|
||||||
{
|
{
|
||||||
Uniforms[0] = { UniformType::Float, Cursor, name };
|
Uniforms[Index++] = { UniformType::Float, Cursor, name };
|
||||||
memcpy(Buffer + Cursor, &data, sizeof(float));
|
memcpy(Buffer + Cursor, &data, sizeof(float));
|
||||||
Cursor += sizeof(float);
|
Cursor += sizeof(float);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Push(const std::string& name, const glm::vec3& data)
|
||||||
|
{
|
||||||
|
Uniforms[Index++] = { UniformType::Float3, Cursor, name };
|
||||||
|
memcpy(Buffer + Cursor, glm::value_ptr(data), sizeof(glm::vec3));
|
||||||
|
Cursor += sizeof(glm::vec3);
|
||||||
|
}
|
||||||
|
|
||||||
void Push(const std::string& name, const glm::vec4& data)
|
void Push(const std::string& name, const glm::vec4& data)
|
||||||
{
|
{
|
||||||
Uniforms[0] = { UniformType::Float4, Cursor, name };
|
Uniforms[Index++] = { UniformType::Float4, Cursor, name };
|
||||||
memcpy(Buffer + Cursor, glm::value_ptr(data), sizeof(glm::vec4));
|
memcpy(Buffer + Cursor, glm::value_ptr(data), sizeof(glm::vec4));
|
||||||
Cursor += sizeof(glm::vec4);
|
Cursor += sizeof(glm::vec4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Push(const std::string& name, const glm::mat4& data)
|
||||||
|
{
|
||||||
|
Uniforms[Index++] = { UniformType::Mat4, Cursor, name };
|
||||||
|
memcpy(Buffer + Cursor, glm::value_ptr(data), sizeof(glm::mat4));
|
||||||
|
Cursor += sizeof(glm::mat4);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PRISM_API Shader
|
class PRISM_API Shader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual void Reload() = 0;
|
||||||
virtual void Bind() = 0;
|
virtual void Bind() = 0;
|
||||||
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) = 0;
|
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) = 0;
|
||||||
|
|
||||||
|
virtual void SetFloat(const std::string& name, float value) = 0;
|
||||||
|
virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0;
|
||||||
|
virtual const std::string& GetName() const = 0;
|
||||||
|
|
||||||
static Shader* Create(const std::string& filepath);
|
static Shader* Create(const std::string& filepath);
|
||||||
|
|
||||||
|
static std::vector<Shader*> s_AllShaders;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,4 +19,23 @@ namespace Prism
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture2D* Texture2D::Create(const std::string& path, bool srgb)
|
||||||
|
{
|
||||||
|
switch (RendererAPI::Current())
|
||||||
|
{
|
||||||
|
case RendererAPIType::None: return nullptr;
|
||||||
|
case RendererAPIType::OpenGL: return new OpenGLTexture2D(path, srgb);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureCube* TextureCube::Create(const std::string& path)
|
||||||
|
{
|
||||||
|
switch (RendererAPI::Current())
|
||||||
|
{
|
||||||
|
case RendererAPIType::None: return nullptr;
|
||||||
|
case RendererAPIType::OpenGL: return new OpenGLTextureCube(path);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#ifndef TEXTURE_H
|
#ifndef TEXTURE_H
|
||||||
#define TEXTURE_H
|
#define TEXTURE_H
|
||||||
|
#include "RendererAPI.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -20,17 +21,38 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Texture() {}
|
virtual ~Texture() {}
|
||||||
|
virtual RendererID GetRendererID() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PRISM_API Texture2D : public Texture
|
class PRISM_API Texture2D : public Texture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Texture2D* Create(TextureFormat format, unsigned int width, unsigned int height);
|
static Texture2D* Create(TextureFormat format, unsigned int width, unsigned int height);
|
||||||
|
static Texture2D* Create(const std::string& path, bool srgb = false);
|
||||||
|
|
||||||
|
virtual void Bind(unsigned int slot = 0) const = 0;
|
||||||
|
|
||||||
virtual TextureFormat GetFormat() const = 0;
|
virtual TextureFormat GetFormat() const = 0;
|
||||||
virtual unsigned int GetWidth() const = 0;
|
virtual unsigned int GetWidth() const = 0;
|
||||||
virtual unsigned int GetHeight() const = 0;
|
virtual unsigned int GetHeight() const = 0;
|
||||||
|
|
||||||
|
virtual const std::string& GetPath() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PRISM_API TextureCube : public Texture
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static TextureCube* Create(const std::string& path);
|
||||||
|
|
||||||
|
virtual void Bind(unsigned int slot = 0) const = 0;
|
||||||
|
|
||||||
|
virtual TextureFormat GetFormat() const = 0;
|
||||||
|
virtual unsigned int GetWidth() const = 0;
|
||||||
|
virtual unsigned int GetHeight() const = 0;
|
||||||
|
|
||||||
|
virtual const std::string& GetPath() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1
Prism/vendor/assimp
vendored
Submodule
5
Prism/vendor/stb/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
file(GLOB STB_SOURCE src/**.c)
|
||||||
|
|
||||||
|
add_library(stb STATIC ${STB_SOURCE})
|
||||||
|
|
||||||
|
target_include_directories(stb PUBLIC src)
|
||||||
5
Prism/vendor/stb/src/stb_image.c
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-10-24.
|
||||||
|
//
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
7988
Prism/vendor/stb/src/stb_image.h
vendored
Normal file
@ -8,5 +8,5 @@ file(COPY ${ASSETS} DESTINATION ${CMAKE_BINARY_DIR}/bin)
|
|||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SRC_SOURCE})
|
add_executable(${PROJECT_NAME} ${SRC_SOURCE})
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Prism)
|
target_link_libraries(${PROJECT_NAME} PRIVATE Prism-static)
|
||||||
#target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_DOCKSPACE)
|
#target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_DOCKSPACE)
|
||||||
@ -21,6 +21,8 @@ static void ImGuiShowHelpMarker(const char* desc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DemoLayer::DemoLayer()
|
DemoLayer::DemoLayer()
|
||||||
|
: m_ClearColor{ 0.1f, 0.1f, 0.1f, 1.0f }, m_Scene(Scene::Spheres),
|
||||||
|
m_Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,24 +32,55 @@ DemoLayer::~DemoLayer()
|
|||||||
|
|
||||||
void DemoLayer::OnAttach()
|
void DemoLayer::OnAttach()
|
||||||
{
|
{
|
||||||
static float vertices[] = {
|
m_SimplePBRShader.reset(Prism::Shader::Create("assets/shaders/simplepbr.glsl"));
|
||||||
-0.5f, -0.5f, 0.0f,
|
m_QuadShader.reset(Prism::Shader::Create("assets/shaders/quad.glsl"));
|
||||||
0.5f, -0.5f, 0.0f,
|
m_HDRShader.reset(Prism::Shader::Create("assets/shaders/hdr.glsl"));
|
||||||
0.0f, 0.5f, 0.0f
|
m_Mesh.reset(new Prism::Mesh("assets/meshes/cerberus.fbx"));
|
||||||
|
m_SphereMesh.reset(new Prism::Mesh("assets/models/Sphere.fbx"));
|
||||||
|
|
||||||
|
// Editor
|
||||||
|
m_CheckerboardTex.reset(Prism::Texture2D::Create("assets/editor/Checkerboard.tga"));
|
||||||
|
|
||||||
|
// Environment
|
||||||
|
m_EnvironmentCubeMap.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga"));
|
||||||
|
m_EnvironmentIrradiance.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Irradiance.tga"));
|
||||||
|
m_BRDFLUT.reset(Prism::Texture2D::Create("assets/textures/BRDF_LUT.tga"));
|
||||||
|
|
||||||
|
m_Framebuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA16F));
|
||||||
|
m_FinalPresentBuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA8));
|
||||||
|
|
||||||
|
// Create Quad
|
||||||
|
float x = -1, y = -1;
|
||||||
|
float width = 2, height = 2;
|
||||||
|
struct QuadVertex
|
||||||
|
{
|
||||||
|
glm::vec3 Position;
|
||||||
|
glm::vec2 TexCoord;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int indices[] = {
|
QuadVertex* data = new QuadVertex[4];
|
||||||
0, 1, 2
|
|
||||||
};
|
|
||||||
|
|
||||||
m_VertexBuffer = std::unique_ptr<Prism::VertexBuffer>(Prism::VertexBuffer::Create());
|
data[0].Position = glm::vec3(x, y, 0);
|
||||||
m_VertexBuffer->SetData(vertices, sizeof(vertices));
|
data[0].TexCoord = glm::vec2(0, 0);
|
||||||
|
|
||||||
m_IndexBuffer = std::unique_ptr<Prism::IndexBuffer>(Prism::IndexBuffer::Create());
|
data[1].Position = glm::vec3(x + width, y, 0);
|
||||||
m_IndexBuffer->SetData(indices, sizeof(indices));
|
data[1].TexCoord = glm::vec2(1, 0);
|
||||||
|
|
||||||
|
data[2].Position = glm::vec3(x + width, y + height, 0);
|
||||||
|
data[2].TexCoord = glm::vec2(1, 1);
|
||||||
|
|
||||||
m_Shader.reset(Prism::Shader::Create("assets/shaders/shader.glsl"));
|
data[3].Position = glm::vec3(x, y + height, 0);
|
||||||
|
data[3].TexCoord = glm::vec2(0, 1);
|
||||||
|
|
||||||
|
m_VertexBuffer.reset(Prism::VertexBuffer::Create());
|
||||||
|
m_VertexBuffer->SetData(data, 4 * sizeof(QuadVertex));
|
||||||
|
|
||||||
|
uint32_t* indices = new uint32_t[6] { 0, 1, 2, 2, 3, 0, };
|
||||||
|
m_IndexBuffer.reset(Prism::IndexBuffer::Create());
|
||||||
|
m_IndexBuffer->SetData(indices, 6 * sizeof(unsigned int));
|
||||||
|
|
||||||
|
m_Light.Direction = { -0.5f, -0.5f, 1.0f };
|
||||||
|
m_Light.Radiance = { 1.0f, 1.0f, 1.0f };
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemoLayer::OnDetach()
|
void DemoLayer::OnDetach()
|
||||||
@ -56,28 +89,114 @@ void DemoLayer::OnDetach()
|
|||||||
|
|
||||||
void DemoLayer::OnUpdate()
|
void DemoLayer::OnUpdate()
|
||||||
{
|
{
|
||||||
Prism::Renderer::Clear(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]);
|
{
|
||||||
|
// THINGS TO LOOK AT:
|
||||||
|
// - BRDF LUT
|
||||||
|
// - Cubemap mips and filtering
|
||||||
|
// - Tonemapping and proper HDR pipeline
|
||||||
|
using namespace Prism;
|
||||||
|
using namespace glm;
|
||||||
|
|
||||||
Prism::UniformBufferDeclaration<sizeof(glm::vec4), 1> buffer;
|
m_Camera.Update();
|
||||||
buffer.Push("u_Color", m_TriangleColor);
|
auto viewProjection = m_Camera.GetProjectionMatrix() * m_Camera.GetViewMatrix();
|
||||||
m_Shader->UploadUniformBuffer(buffer);
|
|
||||||
|
|
||||||
m_Shader->Bind();
|
m_Framebuffer->Bind();
|
||||||
|
Renderer::Clear(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]);
|
||||||
|
|
||||||
|
Prism::UniformBufferDeclaration<sizeof(mat4), 1> quadShaderUB;
|
||||||
|
quadShaderUB.Push("u_InverseVP", inverse(viewProjection));
|
||||||
|
m_QuadShader->UploadUniformBuffer(quadShaderUB);
|
||||||
|
|
||||||
|
m_QuadShader->Bind();
|
||||||
|
// m_EnvironmentIrradiance->Bind(0);
|
||||||
|
m_EnvironmentCubeMap->Bind(0);
|
||||||
m_VertexBuffer->Bind();
|
m_VertexBuffer->Bind();
|
||||||
m_IndexBuffer->Bind();
|
m_IndexBuffer->Bind();
|
||||||
Prism::Renderer::DrawIndexed(3);
|
Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
||||||
|
|
||||||
|
Prism::UniformBufferDeclaration<sizeof(mat4) * 2 + sizeof(vec3) * 4 + sizeof(float) * 8, 14> simplePbrShaderUB;
|
||||||
|
simplePbrShaderUB.Push("u_ViewProjectionMatrix", viewProjection);
|
||||||
|
simplePbrShaderUB.Push("u_ModelMatrix", mat4(1.0f));
|
||||||
|
simplePbrShaderUB.Push("u_AlbedoColor", m_AlbedoInput.Color);
|
||||||
|
simplePbrShaderUB.Push("u_Metalness", m_MetalnessInput.Value);
|
||||||
|
simplePbrShaderUB.Push("u_Roughness", m_RoughnessInput.Value);
|
||||||
|
simplePbrShaderUB.Push("lights.Direction", m_Light.Direction);
|
||||||
|
simplePbrShaderUB.Push("lights.Radiance", m_Light.Radiance * m_LightMultiplier);
|
||||||
|
simplePbrShaderUB.Push("u_CameraPosition", m_Camera.GetPosition());
|
||||||
|
simplePbrShaderUB.Push("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
|
||||||
|
simplePbrShaderUB.Push("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
||||||
|
simplePbrShaderUB.Push("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
||||||
|
simplePbrShaderUB.Push("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
||||||
|
simplePbrShaderUB.Push("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
||||||
|
simplePbrShaderUB.Push("u_EnvMapRotation", m_EnvMapRotation);
|
||||||
|
m_SimplePBRShader->UploadUniformBuffer(simplePbrShaderUB);
|
||||||
|
|
||||||
|
m_EnvironmentCubeMap->Bind(10);
|
||||||
|
m_EnvironmentIrradiance->Bind(11);
|
||||||
|
m_BRDFLUT->Bind(15);
|
||||||
|
|
||||||
|
m_SimplePBRShader->Bind();
|
||||||
|
if (m_AlbedoInput.TextureMap)
|
||||||
|
m_AlbedoInput.TextureMap->Bind(1);
|
||||||
|
if (m_NormalInput.TextureMap)
|
||||||
|
m_NormalInput.TextureMap->Bind(2);
|
||||||
|
if (m_MetalnessInput.TextureMap)
|
||||||
|
m_MetalnessInput.TextureMap->Bind(3);
|
||||||
|
if (m_RoughnessInput.TextureMap)
|
||||||
|
m_RoughnessInput.TextureMap->Bind(4);
|
||||||
|
|
||||||
|
if (m_Scene == Scene::Spheres)
|
||||||
|
{
|
||||||
|
// Metals
|
||||||
|
float roughness = 0.0f;
|
||||||
|
float x = -88.0f;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
m_SimplePBRShader->SetMat4("u_ModelMatrix", translate(mat4(1.0f), vec3(x, 0.0f, 0.0f)));
|
||||||
|
m_SimplePBRShader->SetFloat("u_Roughness", roughness);
|
||||||
|
m_SimplePBRShader->SetFloat("u_Metalness", 1.0f);
|
||||||
|
m_SphereMesh->Render();
|
||||||
|
|
||||||
|
roughness += 0.15f;
|
||||||
|
x += 22.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dielectrics
|
||||||
|
roughness = 0.0f;
|
||||||
|
x = -88.0f;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
m_SimplePBRShader->SetMat4("u_ModelMatrix", translate(mat4(1.0f), vec3(x, 22.0f, 0.0f)));
|
||||||
|
m_SimplePBRShader->SetFloat("u_Roughness", roughness);
|
||||||
|
m_SimplePBRShader->SetFloat("u_Metalness", 0.0f);
|
||||||
|
m_SphereMesh->Render();
|
||||||
|
|
||||||
|
roughness += 0.15f;
|
||||||
|
x += 22.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (m_Scene == Scene::Model)
|
||||||
|
{
|
||||||
|
m_Mesh->Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Framebuffer->Unbind();
|
||||||
|
|
||||||
|
m_FinalPresentBuffer->Bind();
|
||||||
|
m_HDRShader->Bind();
|
||||||
|
m_HDRShader->SetFloat("u_Exposure", m_Exposure);
|
||||||
|
m_Framebuffer->BindTexture();
|
||||||
|
m_VertexBuffer->Bind();
|
||||||
|
m_IndexBuffer->Bind();
|
||||||
|
Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
||||||
|
m_FinalPresentBuffer->Unbind();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemoLayer::OnImGuiRender()
|
void DemoLayer::OnImGuiRender()
|
||||||
{
|
{
|
||||||
static bool show_demo_window = true;
|
#define ENABLE_DOCKSPACE 1
|
||||||
if (show_demo_window)
|
|
||||||
ImGui::ShowDemoWindow(&show_demo_window);
|
|
||||||
|
|
||||||
ImGui::Begin("GameLayer");
|
|
||||||
ImGui::ColorEdit4("Clear Color", m_ClearColor);
|
|
||||||
ImGui::ColorEdit4("Triangle Color", glm::value_ptr(m_TriangleColor));
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
#if ENABLE_DOCKSPACE
|
#if ENABLE_DOCKSPACE
|
||||||
|
|
||||||
@ -189,10 +308,208 @@ void DemoLayer::OnImGuiRender()
|
|||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Editor Panel ------------------------------------------------------------------------------
|
||||||
|
ImGui::Begin("Settings");
|
||||||
|
if (ImGui::TreeNode("Shaders"))
|
||||||
|
{
|
||||||
|
auto& shaders = Prism::Shader::s_AllShaders;
|
||||||
|
for (auto& shader : shaders)
|
||||||
|
{
|
||||||
|
if (ImGui::TreeNode(shader->GetName().c_str()))
|
||||||
|
{
|
||||||
|
std::string buttonName = "Reload##" + shader->GetName();
|
||||||
|
if (ImGui::Button(buttonName.c_str()))
|
||||||
|
shader->Reload();
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model);
|
||||||
|
|
||||||
|
ImGui::ColorEdit4("Clear Color", m_ClearColor);
|
||||||
|
|
||||||
|
ImGui::SliderFloat3("Light Dir", glm::value_ptr(m_Light.Direction), -1, 1);
|
||||||
|
ImGui::ColorEdit3("Light Radiance", glm::value_ptr(m_Light.Radiance));
|
||||||
|
ImGui::SliderFloat("Light Multiplier", &m_LightMultiplier, 0.0f, 5.0f);
|
||||||
|
ImGui::SliderFloat("Exposure", &m_Exposure, 0.0f, 10.0f);
|
||||||
|
auto cameraForward = m_Camera.GetForwardDirection();
|
||||||
|
ImGui::Text("Camera Forward: %.2f, %.2f, %.2f", cameraForward.x, cameraForward.y, cameraForward.z);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
{
|
||||||
|
ImGui::Text("Mesh");
|
||||||
|
std::string fullpath = m_Mesh ? m_Mesh->GetFilePath() : "None";
|
||||||
|
size_t found = fullpath.find_last_of("/\\");
|
||||||
|
std::string path = found != std::string::npos ? fullpath.substr(found + 1) : fullpath;
|
||||||
|
ImGui::Text(path.c_str()); ImGui::SameLine();
|
||||||
|
if (ImGui::Button("...##Mesh"))
|
||||||
|
{
|
||||||
|
std::string filename = Prism::Application::Get().OpenFile("");
|
||||||
|
if (filename != "")
|
||||||
|
m_Mesh.reset(new Prism::Mesh(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::Text("Shader Parameters");
|
||||||
|
ImGui::Checkbox("Radiance Prefiltering", &m_RadiancePrefilter);
|
||||||
|
ImGui::SliderFloat("Env Map Rotation", &m_EnvMapRotation, -360.0f, 360.0f);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
// Textures ------------------------------------------------------------------------------
|
||||||
|
{
|
||||||
|
// Albedo
|
||||||
|
if (ImGui::CollapsingHeader("Albedo", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||||
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||||
|
ImGui::Image(m_AlbedoInput.TextureMap ? (void*)m_AlbedoInput.TextureMap->GetRendererID() : (void*)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
if (m_AlbedoInput.TextureMap)
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||||
|
ImGui::TextUnformatted(m_AlbedoInput.TextureMap->GetPath().c_str());
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::Image((void*)m_AlbedoInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemClicked())
|
||||||
|
{
|
||||||
|
std::string filename = Prism::Application::Get().OpenFile("");
|
||||||
|
if (filename != "")
|
||||||
|
m_AlbedoInput.TextureMap.reset(Prism::Texture2D::Create(filename, m_AlbedoInput.SRGB));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
ImGui::Checkbox("Use##AlbedoMap", &m_AlbedoInput.UseTexture);
|
||||||
|
if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB))
|
||||||
|
{
|
||||||
|
if (m_AlbedoInput.TextureMap)
|
||||||
|
m_AlbedoInput.TextureMap.reset(Prism::Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB));
|
||||||
|
}
|
||||||
|
ImGui::EndGroup();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(m_AlbedoInput.Color), ImGuiColorEditFlags_NoInputs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Normals
|
||||||
|
if (ImGui::CollapsingHeader("Normals", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||||
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||||
|
ImGui::Image(m_NormalInput.TextureMap ? (void*)m_NormalInput.TextureMap->GetRendererID() : (void*)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
if (m_NormalInput.TextureMap)
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||||
|
ImGui::TextUnformatted(m_NormalInput.TextureMap->GetPath().c_str());
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::Image((void*)m_NormalInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemClicked())
|
||||||
|
{
|
||||||
|
std::string filename = Prism::Application::Get().OpenFile("");
|
||||||
|
if (filename != "")
|
||||||
|
m_NormalInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("Use##NormalMap", &m_NormalInput.UseTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Metalness
|
||||||
|
if (ImGui::CollapsingHeader("Metalness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||||
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||||
|
ImGui::Image(m_MetalnessInput.TextureMap ? (void*)m_MetalnessInput.TextureMap->GetRendererID() : (void*)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
if (m_MetalnessInput.TextureMap)
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||||
|
ImGui::TextUnformatted(m_MetalnessInput.TextureMap->GetPath().c_str());
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::Image((void*)m_MetalnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemClicked())
|
||||||
|
{
|
||||||
|
std::string filename = Prism::Application::Get().OpenFile("");
|
||||||
|
if (filename != "")
|
||||||
|
m_MetalnessInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("Use##MetalnessMap", &m_MetalnessInput.UseTexture);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SliderFloat("Value##MetalnessInput", &m_MetalnessInput.Value, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Roughness
|
||||||
|
if (ImGui::CollapsingHeader("Roughness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||||
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
|
||||||
|
ImGui::Image(m_RoughnessInput.TextureMap ? (void*)m_RoughnessInput.TextureMap->GetRendererID() : (void*)m_CheckerboardTex->GetRendererID(), ImVec2(64, 64));
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
if (m_RoughnessInput.TextureMap)
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||||
|
ImGui::TextUnformatted(m_RoughnessInput.TextureMap->GetPath().c_str());
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::Image((void*)m_RoughnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemClicked())
|
||||||
|
{
|
||||||
|
std::string filename = Prism::Application::Get().OpenFile("");
|
||||||
|
if (filename != "")
|
||||||
|
m_RoughnessInput.TextureMap.reset(Prism::Texture2D::Create(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("Use##RoughnessMap", &m_RoughnessInput.UseTexture);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SliderFloat("Value##RoughnessInput", &m_RoughnessInput.Value, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||||
|
ImGui::Begin("Viewport");
|
||||||
|
auto viewportSize = ImGui::GetContentRegionAvail();
|
||||||
|
m_Framebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
|
m_FinalPresentBuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
|
m_Camera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
||||||
|
ImGui::Image((void*)m_FinalPresentBuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||||
|
// ImGui::Image((void*)m_Framebuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||||
|
ImGui::End();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,9 @@
|
|||||||
#define DEMOLAYER_H
|
#define DEMOLAYER_H
|
||||||
|
|
||||||
#include "Prism.h"
|
#include "Prism.h"
|
||||||
|
#include "Prism/Renderer/Camera.h"
|
||||||
|
#include "Prism/Renderer/FrameBuffer.h"
|
||||||
|
#include "Prism/Renderer/Mesh.h"
|
||||||
|
|
||||||
class DemoLayer : public Prism::Layer
|
class DemoLayer : public Prism::Layer
|
||||||
{
|
{
|
||||||
@ -20,12 +23,80 @@ public:
|
|||||||
virtual void OnEvent(Prism::Event& e) override;
|
virtual void OnEvent(Prism::Event& e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float m_ClearColor[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
|
float m_ClearColor[4];
|
||||||
glm::vec4 m_TriangleColor = { 0.4f, 0.5f, 0.6f, 1.0f };
|
|
||||||
|
std::unique_ptr<Prism::Shader> m_Shader;
|
||||||
|
std::unique_ptr<Prism::Shader> m_PBRShader;
|
||||||
|
std::unique_ptr<Prism::Shader> m_SimplePBRShader;
|
||||||
|
std::unique_ptr<Prism::Shader> m_QuadShader;
|
||||||
|
std::unique_ptr<Prism::Shader> m_HDRShader;
|
||||||
|
std::unique_ptr<Prism::Mesh> m_Mesh;
|
||||||
|
std::unique_ptr<Prism::Mesh> m_SphereMesh;
|
||||||
|
std::unique_ptr<Prism::Texture2D> m_BRDFLUT;
|
||||||
|
|
||||||
|
struct AlbedoInput
|
||||||
|
{
|
||||||
|
glm::vec3 Color = { 0.972f, 0.96f, 0.915f }; // Silver, from https://docs.unrealengine.com/en-us/Engine/Rendering/Materials/PhysicallyBased
|
||||||
|
std::unique_ptr<Prism::Texture2D> TextureMap;
|
||||||
|
bool SRGB = true;
|
||||||
|
bool UseTexture = false;
|
||||||
|
};
|
||||||
|
AlbedoInput m_AlbedoInput;
|
||||||
|
|
||||||
|
struct NormalInput
|
||||||
|
{
|
||||||
|
std::unique_ptr<Prism::Texture2D> TextureMap;
|
||||||
|
bool UseTexture = false;
|
||||||
|
};
|
||||||
|
NormalInput m_NormalInput;
|
||||||
|
|
||||||
|
struct MetalnessInput
|
||||||
|
{
|
||||||
|
float Value = 1.0f;
|
||||||
|
std::unique_ptr<Prism::Texture2D> TextureMap;
|
||||||
|
bool UseTexture = false;
|
||||||
|
};
|
||||||
|
MetalnessInput m_MetalnessInput;
|
||||||
|
|
||||||
|
struct RoughnessInput
|
||||||
|
{
|
||||||
|
float Value = 0.5f;
|
||||||
|
std::unique_ptr<Prism::Texture2D> TextureMap;
|
||||||
|
bool UseTexture = false;
|
||||||
|
};
|
||||||
|
RoughnessInput m_RoughnessInput;
|
||||||
|
|
||||||
|
std::unique_ptr<Prism::FrameBuffer> m_Framebuffer, m_FinalPresentBuffer;
|
||||||
|
|
||||||
std::unique_ptr<Prism::VertexBuffer> m_VertexBuffer;
|
std::unique_ptr<Prism::VertexBuffer> m_VertexBuffer;
|
||||||
std::unique_ptr<Prism::IndexBuffer> m_IndexBuffer;
|
std::unique_ptr<Prism::IndexBuffer> m_IndexBuffer;
|
||||||
std::unique_ptr<Prism::Shader> m_Shader;
|
std::unique_ptr<Prism::TextureCube> m_EnvironmentCubeMap, m_EnvironmentIrradiance;
|
||||||
|
|
||||||
|
Prism::Camera m_Camera;
|
||||||
|
|
||||||
|
struct Light
|
||||||
|
{
|
||||||
|
glm::vec3 Direction;
|
||||||
|
glm::vec3 Radiance;
|
||||||
|
};
|
||||||
|
Light m_Light;
|
||||||
|
float m_LightMultiplier = 0.3f;
|
||||||
|
|
||||||
|
// PBR params
|
||||||
|
float m_Exposure = 1.0f;
|
||||||
|
|
||||||
|
bool m_RadiancePrefilter = false;
|
||||||
|
|
||||||
|
float m_EnvMapRotation = 0.0f;
|
||||||
|
|
||||||
|
enum class Scene : uint32_t
|
||||||
|
{
|
||||||
|
Spheres = 0, Model = 1
|
||||||
|
};
|
||||||
|
Scene m_Scene;
|
||||||
|
|
||||||
|
// Editor resources
|
||||||
|
std::unique_ptr<Prism::Texture2D> m_CheckerboardTex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
256
Sandbox/Sandbox/Layer/TestLayer.cpp
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "TestLayer.h"
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "glm/gtc/type_ptr.hpp"
|
||||||
|
#include "Prism/Renderer/Renderer.h"
|
||||||
|
#include "Prism/Renderer/Shader.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void EnableDockSpace(const bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
static bool p_open = true;
|
||||||
|
static bool opt_fullscreen = true;
|
||||||
|
static bool opt_padding = false;
|
||||||
|
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
|
||||||
|
|
||||||
|
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
|
||||||
|
// because it would be confusing to have two docking targets within each others.
|
||||||
|
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
|
||||||
|
if (opt_fullscreen)
|
||||||
|
{
|
||||||
|
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||||
|
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||||
|
ImGui::SetNextWindowSize(viewport->WorkSize);
|
||||||
|
ImGui::SetNextWindowViewport(viewport->ID);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||||
|
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
|
||||||
|
ImGuiWindowFlags_NoMove;
|
||||||
|
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
|
||||||
|
// and handle the pass-thru hole, so we ask Begin() to not render a background.
|
||||||
|
if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
|
||||||
|
window_flags |= ImGuiWindowFlags_NoBackground;
|
||||||
|
|
||||||
|
// Important: note that we proceed even if Begin() returns false (aka window is collapsed).
|
||||||
|
// This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
|
||||||
|
// all active windows docked into it will lose their parent and become undocked.
|
||||||
|
// We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
|
||||||
|
// any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
|
||||||
|
if (!opt_padding)
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||||
|
ImGui::Begin("DockSpace Demo", &p_open, window_flags);
|
||||||
|
if (!opt_padding)
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
if (opt_fullscreen)
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
|
// Submit the DockSpace
|
||||||
|
// REMINDER: THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace()!
|
||||||
|
// MOST REGULAR APPLICATIONS WILL SIMPLY WANT TO CALL DockSpaceOverViewport(). READ COMMENTS ABOVE.
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
||||||
|
{
|
||||||
|
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
|
||||||
|
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show demo options and help
|
||||||
|
if (ImGui::BeginMenuBar())
|
||||||
|
{
|
||||||
|
if (ImGui::BeginMenu("Options"))
|
||||||
|
{
|
||||||
|
// Disabling fullscreen would allow the window to be moved to the front of other windows,
|
||||||
|
// which we can't undo at the moment without finer window depth/z control.
|
||||||
|
ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
|
||||||
|
ImGui::MenuItem("Padding", NULL, &opt_padding);
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "",
|
||||||
|
(dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0))
|
||||||
|
{
|
||||||
|
dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode;
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Flag: NoDockingSplit", "",
|
||||||
|
(dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0))
|
||||||
|
{
|
||||||
|
dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit;
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Flag: NoUndocking", "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0))
|
||||||
|
{
|
||||||
|
dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking;
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0))
|
||||||
|
{
|
||||||
|
dockspace_flags ^= ImGuiDockNodeFlags_NoResize;
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Flag: AutoHideTabBar", "",
|
||||||
|
(dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0))
|
||||||
|
{
|
||||||
|
dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar;
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Flag: PassthruCentralNode", "",
|
||||||
|
(dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen))
|
||||||
|
{
|
||||||
|
dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode;
|
||||||
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Close", NULL, false, p_open != false))
|
||||||
|
p_open = false;
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
if (ImGui::BeginMenu("Help"))
|
||||||
|
{
|
||||||
|
ImGui::TextUnformatted(
|
||||||
|
"This demo has nothing to do with enabling docking!" "\n"
|
||||||
|
"This demo only demonstrate the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window."
|
||||||
|
"\n"
|
||||||
|
"Most application can simply call ImGui::DockSpaceOverViewport() and be done with it.");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TextUnformatted(
|
||||||
|
"When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
|
||||||
|
"- Drag from window title bar or their tab to dock/undock." "\n"
|
||||||
|
"- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
|
||||||
|
"- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
|
||||||
|
"- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)");
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TextUnformatted("More details:");
|
||||||
|
ImGui::Bullet();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking");
|
||||||
|
ImGui::BulletText("Read comments in ShowExampleAppDockSpace()");
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestLayer::TestLayer()
|
||||||
|
:m_Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 1000.0f))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestLayer::OnAttach()
|
||||||
|
{
|
||||||
|
m_FrameBuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA16F));
|
||||||
|
m_FinalPresentBuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA8));
|
||||||
|
|
||||||
|
static float QuadVertex[] = {
|
||||||
|
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
||||||
|
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int QuadIndices[] = {
|
||||||
|
0, 1, 2, 2, 3, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
m_VertexBuffer = std::unique_ptr<Prism::VertexBuffer>(Prism::VertexBuffer::Create());
|
||||||
|
m_VertexBuffer->SetData(QuadVertex, sizeof(QuadVertex));
|
||||||
|
|
||||||
|
m_IndexBuffer = std::unique_ptr<Prism::IndexBuffer>(Prism::IndexBuffer::Create());
|
||||||
|
m_IndexBuffer->SetData(QuadIndices, sizeof(QuadIndices));
|
||||||
|
|
||||||
|
m_SkyBoxTextureCube.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga"));
|
||||||
|
|
||||||
|
m_SkyboxShader.reset(Prism::Shader::Create("assets/shaders/quad.glsl"));
|
||||||
|
m_Shader.reset(Prism::Shader::Create("assets/shaders/demo.glsl"));
|
||||||
|
m_HDRShader.reset(Prism::Shader::Create("assets/shaders/hdr.glsl"));
|
||||||
|
|
||||||
|
m_Mesh.reset(new Prism::Mesh("assets/meshes/cerberus.fbx"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestLayer::OnDetach()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestLayer::OnUpdate()
|
||||||
|
{
|
||||||
|
|
||||||
|
m_Camera.Update();
|
||||||
|
auto viewProjection = m_Camera.GetProjectionMatrix() * m_Camera.GetViewMatrix();
|
||||||
|
|
||||||
|
m_FrameBuffer->Bind();
|
||||||
|
Prism::Renderer::Clear(m_clearColor[0], m_clearColor[1], m_clearColor[2], m_clearColor[3]);
|
||||||
|
|
||||||
|
Prism::UniformBufferDeclaration<sizeof(glm::mat4), 1> skyboxShaderUB;
|
||||||
|
skyboxShaderUB.Push("u_InverseVP", inverse(viewProjection));
|
||||||
|
m_SkyboxShader->UploadUniformBuffer(skyboxShaderUB);
|
||||||
|
m_SkyboxShader->Bind();
|
||||||
|
m_SkyBoxTextureCube->Bind(0);
|
||||||
|
m_VertexBuffer->Bind();
|
||||||
|
m_IndexBuffer->Bind();
|
||||||
|
Prism::Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
||||||
|
|
||||||
|
Prism::UniformBufferDeclaration<sizeof(glm::vec4) + sizeof(glm::mat4), 2> uniformbuffer;
|
||||||
|
uniformbuffer.Push("u_Color", m_TriangleColor);
|
||||||
|
uniformbuffer.Push("u_MVP", viewProjection);
|
||||||
|
m_Shader->UploadUniformBuffer(uniformbuffer);
|
||||||
|
|
||||||
|
m_Shader->Bind();
|
||||||
|
|
||||||
|
m_Mesh->Render();
|
||||||
|
// m_VertexBuffer->Bind();
|
||||||
|
// m_IndexBuffer->Bind();
|
||||||
|
|
||||||
|
// m_Mesh->Render();
|
||||||
|
// Prism::Renderer::DrawIndexed(3, false);
|
||||||
|
m_FrameBuffer->Unbind();
|
||||||
|
|
||||||
|
// HDR
|
||||||
|
m_FinalPresentBuffer->Bind();
|
||||||
|
m_HDRShader->Bind();
|
||||||
|
m_HDRShader->SetFloat("u_Exposure", m_Exposure);
|
||||||
|
m_FrameBuffer->BindTexture();
|
||||||
|
m_VertexBuffer->Bind();
|
||||||
|
m_IndexBuffer->Bind();
|
||||||
|
Prism::Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
||||||
|
m_FinalPresentBuffer->Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestLayer::OnImGuiRender()
|
||||||
|
{
|
||||||
|
EnableDockSpace(true);
|
||||||
|
|
||||||
|
ImGui::Begin("Settings");
|
||||||
|
ImGui::ColorEdit4("ClearColor", glm::value_ptr(m_clearColor));
|
||||||
|
ImGui::ColorEdit4("TriangleClearColor", glm::value_ptr(m_TriangleColor));
|
||||||
|
ImGui::DragFloat("Exposure", &m_Exposure, 0.01f, 0.0f);
|
||||||
|
const auto& position = m_Camera.GetPosition();
|
||||||
|
ImGui::Text("Camera: (%.2f, %.2f, %.2f)", position.x, position.y, position.z);
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||||
|
ImGui::Begin("Viewport");
|
||||||
|
auto viewportSize = ImGui::GetContentRegionAvail();
|
||||||
|
m_FrameBuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
|
m_FinalPresentBuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
|
m_Camera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
||||||
|
ImGui::Image((void*)m_FinalPresentBuffer->GetColorAttachmentRendererID(), viewportSize, {0, 1}, {1, 0});
|
||||||
|
ImGui::End();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestLayer::OnEvent(Prism::Event& e)
|
||||||
|
{
|
||||||
|
}
|
||||||
49
Sandbox/Sandbox/Layer/TestLayer.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TESTLAYER_H
|
||||||
|
#define TESTLAYER_H
|
||||||
|
#include "glm/vec4.hpp"
|
||||||
|
#include "Prism/Core/Layer.h"
|
||||||
|
#include "Prism/Renderer/Buffer.h"
|
||||||
|
#include "Prism/Renderer/Camera.h"
|
||||||
|
#include "Prism/Renderer/FrameBuffer.h"
|
||||||
|
#include "Prism/Renderer/Mesh.h"
|
||||||
|
#include "Prism/Renderer/Shader.h"
|
||||||
|
#include "Prism/Renderer/Texture.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TestLayer : public Prism::Layer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestLayer();
|
||||||
|
void OnAttach() override;
|
||||||
|
void OnDetach() override;
|
||||||
|
void OnUpdate() override;
|
||||||
|
void OnImGuiRender() override;
|
||||||
|
void OnEvent(Prism::Event& e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
glm::vec4 m_clearColor = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
|
||||||
|
glm::vec4 m_TriangleColor = glm::vec4(1.0f);
|
||||||
|
|
||||||
|
std::unique_ptr<Prism::FrameBuffer> m_FrameBuffer, m_FinalPresentBuffer;
|
||||||
|
std::unique_ptr<Prism::VertexBuffer> m_VertexBuffer;
|
||||||
|
std::unique_ptr<Prism::IndexBuffer> m_IndexBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<Prism::TextureCube> m_SkyBoxTextureCube;
|
||||||
|
|
||||||
|
std::unique_ptr<Prism::Shader> m_SkyboxShader;
|
||||||
|
std::unique_ptr<Prism::Shader> m_Shader;
|
||||||
|
std::unique_ptr<Prism::Shader> m_HDRShader;
|
||||||
|
std::unique_ptr<Prism::Mesh> m_Mesh;
|
||||||
|
|
||||||
|
Prism::Camera m_Camera;
|
||||||
|
|
||||||
|
float m_Exposure = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //TESTLAYER_H
|
||||||
@ -7,6 +7,7 @@
|
|||||||
#include "Prism/Core/EntryPoint.h"
|
#include "Prism/Core/EntryPoint.h"
|
||||||
|
|
||||||
#include "Layer/DemoLayer.h"
|
#include "Layer/DemoLayer.h"
|
||||||
|
#include "Layer/TestLayer.h"
|
||||||
|
|
||||||
class Sandbox : public Prism::Application
|
class Sandbox : public Prism::Application
|
||||||
{
|
{
|
||||||
@ -17,7 +18,8 @@ public:
|
|||||||
|
|
||||||
virtual void OnInit() override
|
virtual void OnInit() override
|
||||||
{
|
{
|
||||||
PushLayer(new DemoLayer());
|
PushLayer(new TestLayer());
|
||||||
|
// PushLayer(new DemoLayer());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
BIN
Sandbox/assets/editor/Checkerboard.tga
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
Sandbox/assets/meshes/Anya.fbx
Normal file
BIN
Sandbox/assets/meshes/cerberus.fbx
Normal file
23
Sandbox/assets/meshes/skybox.obj
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Blender v2.78 (sub 0) OBJ File: ''
|
||||||
|
# www.blender.org
|
||||||
|
v 10.000000 -10.000000 -9.999999
|
||||||
|
v 10.000000 -10.000000 10.000000
|
||||||
|
v -10.000001 -10.000000 9.999998
|
||||||
|
v -9.999996 -10.000000 -10.000004
|
||||||
|
v 10.000005 10.000000 -9.999994
|
||||||
|
v 9.999993 10.000000 10.000006
|
||||||
|
v -10.000004 10.000000 9.999996
|
||||||
|
v -9.999999 10.000000 -10.000000
|
||||||
|
vn 0.0000 1.0000 -0.0000
|
||||||
|
vn 0.0000 -1.0000 0.0000
|
||||||
|
vn -1.0000 -0.0000 -0.0000
|
||||||
|
vn 0.0000 0.0000 -1.0000
|
||||||
|
vn 1.0000 0.0000 0.0000
|
||||||
|
vn -0.0000 -0.0000 1.0000
|
||||||
|
s off
|
||||||
|
f 1//1 4//1 3//1 2//1
|
||||||
|
f 5//2 6//2 7//2 8//2
|
||||||
|
f 1//3 2//3 6//3 5//3
|
||||||
|
f 2//4 3//4 7//4 6//4
|
||||||
|
f 3//5 4//5 8//5 7//5
|
||||||
|
f 5//6 8//6 4//6 1//6
|
||||||
BIN
Sandbox/assets/models/Cube.fbx
Normal file
BIN
Sandbox/assets/models/Sphere.fbx
Normal file
BIN
Sandbox/assets/models/SphereOld.fbx
Normal file
29
Sandbox/assets/shaders/demo.glsl
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#type vertex
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 1) in vec3 a_Normal;
|
||||||
|
|
||||||
|
uniform mat4 u_MVP;
|
||||||
|
|
||||||
|
out vec3 v_Normal;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = u_MVP * vec4(a_Position, 1.0);
|
||||||
|
v_Normal = a_Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 o_Color;
|
||||||
|
|
||||||
|
uniform vec4 u_Color;
|
||||||
|
in vec3 v_Normal;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
o_Color = u_Color * vec4(v_Normal * 0.5 + 0.5, 1.0f);
|
||||||
|
// o_Color = vec4(0.6, 0.7, 0.8, 1.0);
|
||||||
|
}
|
||||||
43
Sandbox/assets/shaders/hdr.glsl
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#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, 1.0, 1.0);
|
||||||
|
v_TexCoord = a_TexCoord;
|
||||||
|
gl_Position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
in vec2 v_TexCoord;
|
||||||
|
|
||||||
|
uniform sampler2D u_Texture;
|
||||||
|
|
||||||
|
layout(location=0) out vec4 outColor;
|
||||||
|
|
||||||
|
uniform float u_Exposure;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
const float gamma = 2.2;
|
||||||
|
const float pureWhite = 1.0;
|
||||||
|
|
||||||
|
vec3 color = texture(u_Texture, v_TexCoord).rgb * u_Exposure;
|
||||||
|
// Reinhard tonemapping operator.
|
||||||
|
// see: "Photographic Tone Reproduction for Digital Images", eq. 4
|
||||||
|
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
|
||||||
|
float mappedLuminance = (luminance * (1.0 + luminance / (pureWhite * pureWhite))) / (1.0 + luminance);
|
||||||
|
|
||||||
|
// Scale color by ratio of average luminances.
|
||||||
|
vec3 mappedColor = (mappedLuminance / luminance) * color;
|
||||||
|
|
||||||
|
// Gamma correction.
|
||||||
|
outColor = vec4(pow(mappedColor, vec3(1.0/gamma)), 1.0);
|
||||||
|
}
|
||||||
33
Sandbox/assets/shaders/quad.glsl
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Simple Textured Quad Shader
|
||||||
|
|
||||||
|
#type vertex
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 1) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
uniform mat4 u_InverseVP;
|
||||||
|
|
||||||
|
out vec3 v_Position;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 position = vec4(a_Position.xy, 1.0, 1.0);
|
||||||
|
gl_Position = position;
|
||||||
|
|
||||||
|
v_Position = (u_InverseVP * position).xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 finalColor;
|
||||||
|
|
||||||
|
uniform samplerCube u_Texture;
|
||||||
|
|
||||||
|
in vec3 v_Position;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
finalColor = textureLod(u_Texture, v_Position, 0.0);
|
||||||
|
}
|
||||||
@ -1,21 +1,32 @@
|
|||||||
#type vertex
|
#type vertex
|
||||||
#version 430 core
|
#version 430
|
||||||
|
|
||||||
layout(location = 0) in vec3 a_Position;
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 1) in vec3 a_Normal;
|
||||||
|
layout(location = 2) in vec3 a_Tangent;
|
||||||
|
layout(location = 3) in vec3 a_Bitangent;
|
||||||
|
layout(location = 4) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
uniform mat4 u_MVP;
|
||||||
|
|
||||||
|
out vec3 v_Normal;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = vec4(a_Position, 1.0);
|
gl_Position = u_MVP * vec4(a_Position, 1.0);
|
||||||
|
v_Normal = a_Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
#type fragment
|
#type fragment
|
||||||
#version 430 core
|
#version 430
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Color;
|
layout(location = 0) out vec4 finalColor;
|
||||||
|
|
||||||
uniform vec4 u_Color;
|
//uniform vec4 u_Color;
|
||||||
|
|
||||||
|
in vec3 v_Normal;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
o_Color = u_Color;
|
finalColor = vec4((v_Normal * 0.5 + 0.5), 1.0);// * u_Color.xyz, 1.0);
|
||||||
}
|
}
|
||||||
319
Sandbox/assets/shaders/simplepbr.glsl
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
// -----------------------------
|
||||||
|
// -- 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.
|
||||||
|
// Currently heavily updated.
|
||||||
|
//
|
||||||
|
// 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)
|
||||||
|
// - Frostbite's SIGGRAPH 2014 paper (https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/)
|
||||||
|
// - Michał Siejak's PBR project (https://github.com/Nadrin)
|
||||||
|
// - My implementation from years ago in the Sparky engine (https://github.com/TheCherno/Sparky)
|
||||||
|
#type vertex
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 1) in vec3 a_Normal;
|
||||||
|
layout(location = 2) in vec3 a_Tangent;
|
||||||
|
layout(location = 3) in vec3 a_Binormal;
|
||||||
|
layout(location = 4) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
uniform mat4 u_ViewProjectionMatrix;
|
||||||
|
uniform mat4 u_ModelMatrix;
|
||||||
|
|
||||||
|
out VertexOutput
|
||||||
|
{
|
||||||
|
vec3 WorldPosition;
|
||||||
|
vec3 Normal;
|
||||||
|
vec2 TexCoord;
|
||||||
|
mat3 WorldNormals;
|
||||||
|
} vs_Output;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vs_Output.WorldPosition = vec3(mat4(u_ModelMatrix) * vec4(a_Position, 1.0));
|
||||||
|
vs_Output.Normal = a_Normal;
|
||||||
|
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
|
||||||
|
vs_Output.WorldNormals = mat3(u_ModelMatrix) * mat3(a_Tangent, a_Binormal, a_Normal);
|
||||||
|
|
||||||
|
gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * vec4(a_Position, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
const float PI = 3.141592;
|
||||||
|
const float Epsilon = 0.00001;
|
||||||
|
|
||||||
|
const int LightCount = 1;
|
||||||
|
|
||||||
|
|
||||||
|
// Constant normal incidence Fresnel factor for all dielectrics.
|
||||||
|
const vec3 Fdielectric = vec3(0.04);
|
||||||
|
|
||||||
|
struct Light {
|
||||||
|
vec3 Direction;
|
||||||
|
vec3 Radiance;
|
||||||
|
};
|
||||||
|
|
||||||
|
in VertexOutput
|
||||||
|
{
|
||||||
|
vec3 WorldPosition;
|
||||||
|
vec3 Normal;
|
||||||
|
vec2 TexCoord;
|
||||||
|
mat3 WorldNormals;
|
||||||
|
} vs_Input;
|
||||||
|
|
||||||
|
layout(location=0) out vec4 color;
|
||||||
|
|
||||||
|
uniform Light lights;
|
||||||
|
uniform vec3 u_CameraPosition;
|
||||||
|
|
||||||
|
// PBR texture inputs
|
||||||
|
uniform sampler2D u_AlbedoTexture;
|
||||||
|
uniform sampler2D u_NormalTexture;
|
||||||
|
uniform sampler2D u_MetalnessTexture;
|
||||||
|
uniform sampler2D u_RoughnessTexture;
|
||||||
|
|
||||||
|
// Environment maps
|
||||||
|
uniform samplerCube u_EnvRadianceTex;
|
||||||
|
uniform samplerCube u_EnvIrradianceTex;
|
||||||
|
|
||||||
|
// BRDF LUT
|
||||||
|
uniform sampler2D u_BRDFLUTTexture;
|
||||||
|
|
||||||
|
uniform vec3 u_AlbedoColor;
|
||||||
|
uniform float u_Metalness;
|
||||||
|
uniform float u_Roughness;
|
||||||
|
|
||||||
|
uniform float u_EnvMapRotation;
|
||||||
|
|
||||||
|
// Toggles
|
||||||
|
uniform float u_RadiancePrefilter;
|
||||||
|
uniform float u_AlbedoTexToggle;
|
||||||
|
uniform float u_NormalTexToggle;
|
||||||
|
uniform float u_MetalnessTexToggle;
|
||||||
|
uniform float u_RoughnessTexToggle;
|
||||||
|
|
||||||
|
struct PBRParameters
|
||||||
|
{
|
||||||
|
vec3 Albedo;
|
||||||
|
float Roughness;
|
||||||
|
float Metalness;
|
||||||
|
|
||||||
|
vec3 Normal;
|
||||||
|
vec3 View;
|
||||||
|
float NdotV;
|
||||||
|
};
|
||||||
|
|
||||||
|
PBRParameters m_Params;
|
||||||
|
|
||||||
|
// GGX/Towbridge-Reitz normal distribution function.
|
||||||
|
// Uses Disney's reparametrization of alpha = roughness^2
|
||||||
|
float ndfGGX(float cosLh, float roughness)
|
||||||
|
{
|
||||||
|
float alpha = roughness * roughness;
|
||||||
|
float alphaSq = alpha * alpha;
|
||||||
|
|
||||||
|
float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0;
|
||||||
|
return alphaSq / (PI * denom * denom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 r = (roughness + 1.0);
|
||||||
|
float k = (r*r) / 8.0;
|
||||||
|
|
||||||
|
float nom = NdotV;
|
||||||
|
float denom = NdotV * (1.0 - k) + k;
|
||||||
|
|
||||||
|
return nom / denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
|
||||||
|
{
|
||||||
|
float NdotV = max(dot(N, V), 0.0);
|
||||||
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
|
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||||
|
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||||
|
|
||||||
|
return ggx1 * ggx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shlick's approximation of the Fresnel factor.
|
||||||
|
vec3 fresnelSchlick(vec3 F0, float cosTheta)
|
||||||
|
{
|
||||||
|
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fresnelSchlickRoughness(vec3 F0, float cosTheta, float roughness)
|
||||||
|
{
|
||||||
|
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 Hammersley(uint i, uint N)
|
||||||
|
{
|
||||||
|
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
|
||||||
|
{
|
||||||
|
float a = Roughness * Roughness;
|
||||||
|
float Phi = 2 * PI * Xi.x;
|
||||||
|
float CosTheta = sqrt( (1 - Xi.y) / ( 1 + (a*a - 1) * Xi.y ) );
|
||||||
|
float SinTheta = sqrt( 1 - CosTheta * CosTheta );
|
||||||
|
vec3 H;
|
||||||
|
H.x = SinTheta * cos( Phi );
|
||||||
|
H.y = SinTheta * sin( Phi );
|
||||||
|
H.z = CosTheta;
|
||||||
|
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 );
|
||||||
|
// Tangent to world space
|
||||||
|
return TangentX * H.x + TangentY * H.y + N * H.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
float TotalWeight = 0.0;
|
||||||
|
|
||||||
|
vec3 PrefilterEnvMap(float Roughness, vec3 R)
|
||||||
|
{
|
||||||
|
vec3 N = R;
|
||||||
|
vec3 V = R;
|
||||||
|
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 RotateVectorAboutY(float angle, vec3 vec)
|
||||||
|
{
|
||||||
|
angle = radians(angle);
|
||||||
|
mat3x3 rotationMatrix ={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 Lighting(vec3 F0)
|
||||||
|
{
|
||||||
|
vec3 result = vec3(0.0);
|
||||||
|
for(int i = 0; i < LightCount; i++)
|
||||||
|
{
|
||||||
|
vec3 Li = -lights.Direction;
|
||||||
|
vec3 Lradiance = lights.Radiance;
|
||||||
|
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 irradiance = texture(u_EnvIrradianceTex, m_Params.Normal).rgb;
|
||||||
|
vec3 F = fresnelSchlickRoughness(F0, m_Params.NdotV, m_Params.Roughness);
|
||||||
|
vec3 kd = (1.0 - F) * (1.0 - m_Params.Metalness);
|
||||||
|
vec3 diffuseIBL = m_Params.Albedo * irradiance;
|
||||||
|
|
||||||
|
int u_EnvRadianceTexLevels = textureQueryLevels(u_EnvRadianceTex);
|
||||||
|
float NoV = clamp(m_Params.NdotV, 0.0, 1.0);
|
||||||
|
vec3 R = 2.0 * dot(m_Params.View, m_Params.Normal) * m_Params.Normal - m_Params.View;
|
||||||
|
vec3 specularIrradiance = vec3(0.0);
|
||||||
|
|
||||||
|
if (u_RadiancePrefilter > 0.5)
|
||||||
|
specularIrradiance = PrefilterEnvMap(m_Params.Roughness * m_Params.Roughness, R) * u_RadiancePrefilter;
|
||||||
|
else
|
||||||
|
specularIrradiance = textureLod(u_EnvRadianceTex, RotateVectorAboutY(u_EnvMapRotation, Lr), sqrt(m_Params.Roughness) * u_EnvRadianceTexLevels).rgb * (1.0 - u_RadiancePrefilter);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
vec3 specularIBL = specularIrradiance * (F * specularBRDF.x + specularBRDF.y);
|
||||||
|
|
||||||
|
return kd * diffuseIBL + specularIBL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// 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.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
|
||||||
|
|
||||||
|
// Normals (either from vertex or map)
|
||||||
|
m_Params.Normal = normalize(vs_Input.Normal);
|
||||||
|
if (u_NormalTexToggle > 0.5)
|
||||||
|
{
|
||||||
|
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.View = normalize(u_CameraPosition - vs_Input.WorldPosition);
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Fresnel reflectance, metals use albedo
|
||||||
|
vec3 F0 = mix(Fdielectric, m_Params.Albedo, m_Params.Metalness);
|
||||||
|
|
||||||
|
vec3 lightContribution = Lighting(F0);
|
||||||
|
vec3 iblContribution = IBL(F0, Lr);
|
||||||
|
|
||||||
|
color = vec4(lightContribution + iblContribution, 1.0);
|
||||||
|
}
|
||||||
BIN
Sandbox/assets/textures/BRDF_LUT.tga
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
Sandbox/assets/textures/SphereAlbedo.tga
Normal file
|
After Width: | Height: | Size: 256 KiB |
BIN
Sandbox/assets/textures/SphereMetalness.tga
Normal file
|
After Width: | Height: | Size: 256 KiB |
BIN
Sandbox/assets/textures/SphereRoughness.tga
Normal file
|
After Width: | Height: | Size: 256 KiB |
BIN
Sandbox/assets/textures/cerberus/cerberus_A.png
Normal file
|
After Width: | Height: | Size: 15 MiB |
BIN
Sandbox/assets/textures/cerberus/cerberus_M.png
Normal file
|
After Width: | Height: | Size: 6.5 MiB |
BIN
Sandbox/assets/textures/cerberus/cerberus_N.png
Normal file
|
After Width: | Height: | Size: 19 MiB |
BIN
Sandbox/assets/textures/cerberus/cerberus_R.png
Normal file
|
After Width: | Height: | Size: 11 MiB |
|
After Width: | Height: | Size: 576 KiB |
|
After Width: | Height: | Size: 22 MiB |