From 4c7b79ec8afaec92987020f9eef7c36b594cea5e Mon Sep 17 00:00:00 2001 From: Atdunbg Date: Fri, 28 Nov 2025 23:32:07 +0800 Subject: [PATCH] add static and animation PBR shader, improve [camera renderer material] class --- Prism/src/Prism/Core/Application.cpp | 1 + Prism/src/Prism/Core/Core.h | 6 + Prism/src/Prism/Core/Window.h | 1 + .../Platform/OpenGL/OpenGLFrameBuffer.cpp | 6 +- .../Prism/Platform/OpenGL/OpenGLFrameBuffer.h | 2 +- .../Platform/OpenGL/OpenGLRendererAPI.cpp | 1 + .../Prism/Platform/OpenGL/OpenGLShader.cpp | 8 +- .../src/Prism/Platform/OpenGL/OpenGLShader.h | 2 +- .../Prism/Platform/Windows/WindowsWindow.cpp | 7 + .../Prism/Platform/Windows/WindowsWindow.h | 1 + Prism/src/Prism/Renderer/Buffer.h | 2 +- Prism/src/Prism/Renderer/Camera.cpp | 46 +- Prism/src/Prism/Renderer/Camera.h | 9 +- Prism/src/Prism/Renderer/Material.cpp | 9 + Prism/src/Prism/Renderer/Material.h | 8 +- Prism/src/Prism/Renderer/Mesh.cpp | 299 +++++++---- Prism/src/Prism/Renderer/Mesh.h | 27 +- Prism/src/Prism/Renderer/Renderer.cpp | 4 + Prism/src/Prism/Renderer/Renderer.h | 4 + Prism/src/Prism/Renderer/Shader.cpp | 45 +- Prism/src/Prism/Renderer/Shader.h | 21 +- Sandbox/Sandbox/Layer/DemoLayer.cpp | 502 +++++++++--------- Sandbox/Sandbox/Layer/DemoLayer.h | 15 +- Sandbox/Sandbox/Layer/TestLayer.cpp | 8 +- Sandbox/Sandbox/Layer/TestLayer.h | 16 +- Sandbox/Sandbox/Sandbox.cpp | 4 +- Sandbox/assets/shaders/Grid.glsl | 1 - .../{simplepbr.glsl => simplepbr_Anim.glsl} | 0 Sandbox/assets/shaders/simplepbr_Static.glsl | 321 +++++++++++ 29 files changed, 982 insertions(+), 394 deletions(-) rename Sandbox/assets/shaders/{simplepbr.glsl => simplepbr_Anim.glsl} (100%) create mode 100644 Sandbox/assets/shaders/simplepbr_Static.glsl diff --git a/Prism/src/Prism/Core/Application.cpp b/Prism/src/Prism/Core/Application.cpp index dbfec87..520374b 100644 --- a/Prism/src/Prism/Core/Application.cpp +++ b/Prism/src/Prism/Core/Application.cpp @@ -36,6 +36,7 @@ namespace Prism PushOverlay(m_ImGuiLayer); Renderer::Init(); + Renderer::Get().WaitAndRender(); } Application::~Application() diff --git a/Prism/src/Prism/Core/Core.h b/Prism/src/Prism/Core/Core.h index da8ba6c..ae6d232 100644 --- a/Prism/src/Prism/Core/Core.h +++ b/Prism/src/Prism/Core/Core.h @@ -63,6 +63,12 @@ namespace Prism template using Ref = std::shared_ptr; + + template + constexpr Ref CreateRef(Args&& ... args) + { + return std::make_shared(std::forward(args)...); + } } #endif //CORE_H diff --git a/Prism/src/Prism/Core/Window.h b/Prism/src/Prism/Core/Window.h index 3777350..e266afd 100644 --- a/Prism/src/Prism/Core/Window.h +++ b/Prism/src/Prism/Core/Window.h @@ -38,6 +38,7 @@ namespace Prism virtual void SetEventCallback(const EventCallbackFn& callback) = 0; virtual unsigned int GetWidth() const = 0; virtual unsigned int GetHeight() const = 0; + virtual std::pair GetWindowPos() const = 0; virtual void SetVSync(bool enable) = 0; virtual bool const IsVSync() const = 0; diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp index 5173146..ac84674 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.cpp @@ -11,9 +11,11 @@ namespace Prism { OpenGLFrameBuffer::OpenGLFrameBuffer(const uint32_t width, const uint32_t height, const FramebufferFormat format) - : m_Width(width), m_Height(height), m_Format(format) + : m_Format(format) { - Resize(width, height); + OpenGLFrameBuffer::Resize(width, height); + m_Width = width; + m_Height = height; } OpenGLFrameBuffer::~OpenGLFrameBuffer() diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.h b/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.h index cec6e90..dbe4b42 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLFrameBuffer.h @@ -31,7 +31,7 @@ namespace Prism virtual FramebufferFormat GetFormat() const { return m_Format; } private: RendererID m_RendererID = 0; - uint32_t m_Width, m_Height; + uint32_t m_Width = 0, m_Height = 0; FramebufferFormat m_Format; RendererID m_ColorAttachment, m_DepthAttachment; diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp index 44ff07a..a76ad67 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp @@ -27,6 +27,7 @@ namespace Prism void RendererAPI::Init() { glDebugMessageCallback(OpenGLLogMessage, nullptr); + glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); unsigned int vao; diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLShader.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLShader.cpp index 6c6c511..e56eff2 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLShader.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLShader.cpp @@ -12,9 +12,13 @@ namespace Prism OpenGLShader::OpenGLShader(const std::string& filepath) : m_AssetPath(filepath) { - const size_t found = filepath.find_last_of("/\\"); + size_t found = filepath.find_last_of("/\\"); m_Name = found != std::string::npos ? filepath.substr(found + 1) : filepath; - OpenGLShader::Reload(); + + found = m_Name.find_last_of('.'); + m_Name = found != std::string::npos ? m_Name.substr(0, found) : m_Name; + + OpenGLShader::Reload(); } diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLShader.h b/Prism/src/Prism/Platform/OpenGL/OpenGLShader.h index cffae5c..72ef306 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLShader.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLShader.h @@ -83,7 +83,7 @@ namespace Prism inline const ShaderUniformBufferDeclaration& GetPSMaterialUniformBuffer() const override { return *m_PSMaterialUniformBuffer; } inline const ShaderResourceList& GetResources() const override { return m_Resources; } private: - RendererID m_RendererID; + RendererID m_RendererID = 0; bool m_Loaded = false; diff --git a/Prism/src/Prism/Platform/Windows/WindowsWindow.cpp b/Prism/src/Prism/Platform/Windows/WindowsWindow.cpp index 4a991f6..4c0285a 100644 --- a/Prism/src/Prism/Platform/Windows/WindowsWindow.cpp +++ b/Prism/src/Prism/Platform/Windows/WindowsWindow.cpp @@ -58,6 +58,13 @@ namespace Prism m_Data.VSync = enable; } + std::pair WindowsWindow::GetWindowPos() const + { + int x, y; + glfwGetWindowPos(m_Window, &x, &y); + return { x, y }; + } + void WindowsWindow::Init(const WindowProps& props) { m_Data.Title = props.Title; diff --git a/Prism/src/Prism/Platform/Windows/WindowsWindow.h b/Prism/src/Prism/Platform/Windows/WindowsWindow.h index c8a3cf3..47e11bd 100644 --- a/Prism/src/Prism/Platform/Windows/WindowsWindow.h +++ b/Prism/src/Prism/Platform/Windows/WindowsWindow.h @@ -24,6 +24,7 @@ namespace Prism inline void SetEventCallback(const EventCallbackFn& callback) override { m_Data.EventCallback = callback; } bool const IsVSync() const override { return m_Data.VSync; } void SetVSync(bool enable) override; + virtual std::pair GetWindowPos() const override; inline void* GetNativeWindow() const { return m_Window; } diff --git a/Prism/src/Prism/Renderer/Buffer.h b/Prism/src/Prism/Renderer/Buffer.h index 761c25e..1a5b70f 100644 --- a/Prism/src/Prism/Renderer/Buffer.h +++ b/Prism/src/Prism/Renderer/Buffer.h @@ -14,7 +14,7 @@ namespace Prism public: virtual ~VertexBuffer() {} - virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0) = 0; + virtual void SetData(void* buffer, uint32_t size, uint32_t offset = 0) = 0; virtual void Bind() const = 0; virtual unsigned int GetSize() const = 0; diff --git a/Prism/src/Prism/Renderer/Camera.cpp b/Prism/src/Prism/Renderer/Camera.cpp index e584041..61902b7 100644 --- a/Prism/src/Prism/Renderer/Camera.cpp +++ b/Prism/src/Prism/Renderer/Camera.cpp @@ -22,11 +22,6 @@ namespace Prism Camera::Camera(const glm::mat4& projectionMatrix) : m_ProjectionMatrix(projectionMatrix) { - // Sensible defaults - m_PanSpeed = 0.15f; - m_RotationSpeed = 0.5f; - m_ZoomSpeed = 10.0f; - m_Position = { 0, 0, 10 }; m_Rotation = glm::vec3(90.0f, 0.0f, 0.0f); @@ -85,23 +80,25 @@ namespace Prism 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; + auto [xSpeed, ySpeed] = PanSpeed(); + // PM_CORE_TRACE("{0}, {1}", xSpeed, ySpeed); + m_FocalPoint += -GetRightDirection() * delta.x * xSpeed * m_Distance; + m_FocalPoint += GetUpDirection() * delta.y * ySpeed * 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; + m_Yaw += yawSign * delta.x * RotationSpeed(); + m_Pitch += delta.y * RotationSpeed(); } - void Camera::MouseZoom(float delta) + void Camera::MouseZoom(const float delta) { - m_Distance -= delta * m_ZoomSpeed; + m_Distance -= delta * ZoomSpeed(); if (m_Distance < 1.0f) { - m_FocalPoint += GetForwardDirection(); + m_FocalPoint += GetForwardDirection() * delta; m_Distance = 1.0f; } } @@ -115,4 +112,29 @@ namespace Prism { return glm::quat(glm::vec3(-m_Pitch, -m_Yaw, 0.0f)); } + + std::pair Camera::PanSpeed() const + { + const float x = std::min(m_ViewportWidth / 1000.0f, 2.4f); // max = 2.4f + float xFactor = 0.0366f * (x * x) - 0.1778f * x + 0.3021f; + + const float y = std::min(m_ViewportHeight / 1000.0f, 2.4f); // max = 2.4f + float yFactor = 0.0366f * (y * y) - 0.1778f * y + 0.3021f; + + return { xFactor, yFactor }; + } + + float Camera::RotationSpeed() const + { + return 0.8f; + } + + float Camera::ZoomSpeed() const + { + float distance = m_Distance * 0.2f; + distance = std::max(distance, 0.0f); + float speed = distance * distance; + speed = std::min(speed, 100.0f); // max speed = 100 + return speed; + } } diff --git a/Prism/src/Prism/Renderer/Camera.h b/Prism/src/Prism/Renderer/Camera.h index 415f8e4..5cbce2f 100644 --- a/Prism/src/Prism/Renderer/Camera.h +++ b/Prism/src/Prism/Renderer/Camera.h @@ -32,6 +32,8 @@ namespace Prism glm::vec3 GetRightDirection(); glm::vec3 GetForwardDirection(); const glm::vec3& GetPosition() const { return m_Position; } + public: + inline void SetViewportSize(const uint32_t width, const uint32_t height) { m_ViewportWidth = width; m_ViewportHeight = height; } private: void MousePan(const glm::vec2& delta); void MouseRotate(const glm::vec2& delta); @@ -39,6 +41,10 @@ namespace Prism glm::vec3 CalculatePosition(); glm::quat GetOrientation(); + + std::pair PanSpeed() const; + float RotationSpeed() const; + float ZoomSpeed() const; private: glm::mat4 m_ProjectionMatrix, m_ViewMatrix; glm::vec3 m_Position, m_Rotation, m_FocalPoint; @@ -47,8 +53,9 @@ namespace Prism glm::vec2 m_InitialMousePosition; glm::vec3 m_InitialFocalPoint, m_InitialRotation; + uint32_t m_ViewportWidth = 1280, m_ViewportHeight = 720; + float m_Distance; - float m_PanSpeed, m_RotationSpeed, m_ZoomSpeed; float m_Pitch, m_Yaw; }; diff --git a/Prism/src/Prism/Renderer/Material.cpp b/Prism/src/Prism/Renderer/Material.cpp index 5f7ed81..9c444c1 100644 --- a/Prism/src/Prism/Renderer/Material.cpp +++ b/Prism/src/Prism/Renderer/Material.cpp @@ -17,6 +17,10 @@ namespace Prism { } + Ref Material::Create(const Ref& shader) + { + return CreateRef(shader); + } void Material::AllocateStorage() @@ -120,6 +124,11 @@ namespace Prism m_Material->m_MaterialInstances.erase(this); } + Ref MaterialInstance::Create(const Ref& material) + { + return CreateRef(material); + } + void MaterialInstance::OnShaderReloaded() { AllocateStorage(); diff --git a/Prism/src/Prism/Renderer/Material.h b/Prism/src/Prism/Renderer/Material.h index ebfa659..6ab5e9e 100644 --- a/Prism/src/Prism/Renderer/Material.h +++ b/Prism/src/Prism/Renderer/Material.h @@ -23,6 +23,8 @@ namespace Prism Material(const Ref& shader); virtual ~Material(); + static Ref Create(const Ref& shader); + void Bind() const; template @@ -31,7 +33,8 @@ namespace Prism void Set(const std::string& name, const Ref& texture) { - auto decl = FindResourceDeclaration(name); + const auto decl = FindResourceDeclaration(name); + if (!decl) return; uint32_t slot = decl->GetRegister(); if (m_Textures.size() <= slot) m_Textures.resize((size_t)slot + 1); @@ -55,6 +58,7 @@ namespace Prism ShaderUniformDeclaration* FindUniformDeclaration(const std::string& name); ShaderResourceDeclaration* FindResourceDeclaration(const std::string& name); Buffer& GetUniformBufferTarget(ShaderUniformDeclaration* uniformDeclaration); + private: Ref m_Shader; std::unordered_set m_MaterialInstances; @@ -75,6 +79,8 @@ namespace Prism MaterialInstance(const Ref& material); virtual ~MaterialInstance(); + static Ref Create(const Ref& material); + template void Set(const std::string& name, const T& value) { diff --git a/Prism/src/Prism/Renderer/Mesh.cpp b/Prism/src/Prism/Renderer/Mesh.cpp index 6d059a9..7ab3d97 100644 --- a/Prism/src/Prism/Renderer/Mesh.cpp +++ b/Prism/src/Prism/Renderer/Mesh.cpp @@ -57,7 +57,7 @@ namespace Prism } - void Vertex::AddBoneData(uint32_t BoneID, float Weight) + void AnimatedVertex::AddBoneData(uint32_t BoneID, float Weight) { for (size_t i = 0; i < 4; i++) { @@ -103,6 +103,9 @@ namespace Prism PM_CORE_ERROR("Failed to load mesh file: {0}", filename); + m_IsAnimated = scene->mAnimations != nullptr; + m_MeshShader = m_IsAnimated ? Renderer::GetShaderLibrary()->Get("simplepbr_Anim") : Renderer::GetShaderLibrary()->Get("simplepbr_Static"); + m_Material.reset(new Prism::Material(m_MeshShader)); m_InverseTransform = glm::inverse(aiMatrix4x4ToGlm(scene->mRootNode->mTransformation)); uint32_t vertexCount = 0; @@ -127,21 +130,43 @@ namespace Prism PM_CORE_ASSERT(mesh->HasNormals(), "Meshes require normals."); // Vertices - for (size_t i = 0; i < mesh->mNumVertices; i++) + if (m_IsAnimated) { - 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()) + for (size_t i = 0; i < mesh->mNumVertices; i++) { - 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 }; - } + AnimatedVertex 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->HasTextureCoords(0)) - vertex.Texcoord = { mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y }; - m_Vertices.push_back(vertex); + 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_AnimatedVertices.push_back(vertex); + } + }else + { + for (size_t i = 0; i < mesh->mNumVertices; 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_StaticVertices.push_back(vertex); + } } // Indices @@ -152,45 +177,57 @@ namespace Prism } } + + PM_CORE_TRACE("NODES:"); + PM_CORE_TRACE("-----------------------------"); + TraverseNodes(scene->mRootNode); + PM_CORE_TRACE("-----------------------------"); + // Bones - for (size_t m = 0; m < scene->mNumMeshes; m++) + if (m_IsAnimated) { - aiMesh* mesh = scene->mMeshes[m]; - Submesh& submesh = m_Submeshes[m]; - - for (size_t i = 0; i < mesh->mNumBones; i++) + for (size_t m = 0; m < scene->mNumMeshes; m++) { - aiBone* bone = mesh->mBones[i]; - std::string boneName(bone->mName.data); - int boneIndex = 0; + aiMesh* mesh = scene->mMeshes[m]; + Submesh& submesh = m_Submeshes[m]; - if (m_BoneMapping.find(boneName) == m_BoneMapping.end()) + for (size_t i = 0; i < mesh->mNumBones; i++) { - // Allocate an index for a new bone - boneIndex = m_BoneCount; - m_BoneCount++; - BoneInfo bi; - m_BoneInfo.push_back(bi); - m_BoneInfo[boneIndex].BoneOffset = aiMatrix4x4ToGlm(bone->mOffsetMatrix); - m_BoneMapping[boneName] = boneIndex; - } - else - { - PM_CORE_TRACE("Found existing bone in map"); - boneIndex = m_BoneMapping[boneName]; - } + aiBone* bone = mesh->mBones[i]; + std::string boneName(bone->mName.data); + int boneIndex = 0; - for (size_t j = 0; j < bone->mNumWeights; j++) - { - int VertexID = submesh.BaseVertex + bone->mWeights[j].mVertexId; - float Weight = bone->mWeights[j].mWeight; - m_Vertices[VertexID].AddBoneData(boneIndex, Weight); + if (m_BoneMapping.find(boneName) == m_BoneMapping.end()) + { + // Allocate an index for a new bone + boneIndex = m_BoneCount; + m_BoneCount++; + BoneInfo bi; + m_BoneInfo.push_back(bi); + m_BoneInfo[boneIndex].BoneOffset = aiMatrix4x4ToGlm(bone->mOffsetMatrix); + m_BoneMapping[boneName] = boneIndex; + } + else + { + PM_CORE_TRACE("Found existing bone in map"); + boneIndex = m_BoneMapping[boneName]; + } + + for (size_t j = 0; j < bone->mNumWeights; j++) + { + int VertexID = submesh.BaseVertex + bone->mWeights[j].mVertexId; + float Weight = bone->mWeights[j].mWeight; + m_AnimatedVertices[VertexID].AddBoneData(boneIndex, Weight); + } } } } m_VertexBuffer.reset(VertexBuffer::Create()); - m_VertexBuffer->SetData(m_Vertices.data(), m_Vertices.size() * sizeof(Vertex)); + if (m_IsAnimated) + m_VertexBuffer->SetData(m_AnimatedVertices.data(), m_AnimatedVertices.size() * sizeof(AnimatedVertex)); + else + m_VertexBuffer->SetData(m_StaticVertices.data(), m_StaticVertices.size() * sizeof(Vertex)); m_IndexBuffer.reset(IndexBuffer::Create()); m_IndexBuffer->SetData(m_Indices.data(), m_Indices.size() * sizeof(Index)); @@ -202,59 +239,93 @@ namespace Prism { } - void Mesh::Render(TimeStep deltaTime, Shader* shader) + void Mesh::Render(TimeStep deltaTime, const Ref& materialInstance) { - if (m_AnimationPlaying && m_Scene->mAnimations) - { - m_WorldTime += deltaTime; + Render(deltaTime, glm::mat4(1.0f), materialInstance); + } - float ticksPerSecond = (float)(m_Scene->mAnimations[0]->mTicksPerSecond != 0 ? m_Scene->mAnimations[0]->mTicksPerSecond : 25.0f) * m_TimeMultiplier; - m_AnimationTime += deltaTime * ticksPerSecond; - m_AnimationTime = fmod(m_AnimationTime, (float)m_Scene->mAnimations[0]->mDuration); - } + void Mesh::Render(TimeStep deltaTime, const glm::mat4& transform, const Ref& materialInstance) + { + if (m_IsAnimated) + { + if (m_AnimationPlaying) + { + m_WorldTime += deltaTime; + + float ticksPerSecond = (float)(m_Scene->mAnimations[0]->mTicksPerSecond != 0 ? m_Scene->mAnimations[0]->mTicksPerSecond : 25.0f) * m_TimeMultiplier; + m_AnimationTime += deltaTime * ticksPerSecond; + m_AnimationTime = fmod(m_AnimationTime, (float)m_Scene->mAnimations[0]->mDuration); + } - if (m_Scene->mAnimations) BoneTransform(m_AnimationTime); + } + + if (materialInstance) + materialInstance->Bind(); // TODO: Sort this out m_VertexBuffer->Bind(); m_IndexBuffer->Bind(); + bool materialOverride = !!materialInstance; + // TODO: replace with render API calls - PM_RENDER_S1(shader, { - for (Submesh& submesh : self->m_Submeshes) + PM_RENDER_S2(transform, materialOverride,{ + for (const Submesh& submesh : self->m_Submeshes) { - 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)); - - glEnableVertexAttribArray(5); - glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (const void*)offsetof(Vertex, IDs)); - - glEnableVertexAttribArray(6); - glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Weights)); - - if (self->m_Scene->mAnimations) + if (self->m_IsAnimated) { - for (size_t i = 0; i < self->m_BoneTransforms.size(); i++) - { - std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]"); - shader->SetMat4FromRenderThread(uniformName, self->m_BoneTransforms[i]); - } + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Position)); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Normal)); + + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Tangent)); + + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Binormal)); + + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Texcoord)); + + glEnableVertexAttribArray(5); + glVertexAttribIPointer(5, 4, GL_INT, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, IDs)); + + glEnableVertexAttribArray(6); + glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Weights)); + + if (self->m_Scene->mAnimations) + { + for (size_t i = 0; i < self->m_BoneTransforms.size(); i++) + { + std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]"); + self->m_MeshShader->SetMat4FromRenderThread(uniformName, self->m_BoneTransforms[i]); + } + } + glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex); + }else + { + 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)); } - glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex); - } + if (!materialOverride) + self->m_MeshShader->SetMat4FromRenderThread("u_ModelMatrix", transform * submesh.Transform); + glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex); + } }); } @@ -263,13 +334,16 @@ namespace Prism ImGui::Begin("Mesh Debug"); if (ImGui::CollapsingHeader(m_FilePath.c_str())) { - if (ImGui::CollapsingHeader("Animation")) + if (m_IsAnimated) { - if (ImGui::Button(m_AnimationPlaying ? "Pause" : "Play")) - m_AnimationPlaying = !m_AnimationPlaying; + if (ImGui::CollapsingHeader("Animation")) + { + if (ImGui::Button(m_AnimationPlaying ? "Pause" : "Play")) + m_AnimationPlaying = !m_AnimationPlaying; - ImGui::SliderFloat("##AnimationTime", &m_AnimationTime, 0.0f, (float)m_Scene->mAnimations[0]->mDuration); - ImGui::DragFloat("Time Scale", &m_TimeMultiplier, 0.05f, 0.0f, 10.0f); + ImGui::SliderFloat("##AnimationTime", &m_AnimationTime, 0.0f, (float)m_Scene->mAnimations[0]->mDuration); + ImGui::DragFloat("Time Scale", &m_TimeMultiplier, 0.05f, 0.0f, 10.0f); + } } } @@ -282,16 +356,32 @@ namespace Prism PM_CORE_TRACE("------------------------------------------------------"); PM_CORE_TRACE("Vertex Buffer Dump"); PM_CORE_TRACE("Mesh: {0}", m_FilePath); - for (size_t i = 0; i < m_Vertices.size(); i++) + if (m_IsAnimated) { - auto& vertex = m_Vertices[i]; - PM_CORE_TRACE("Vertex: {0}", i); - PM_CORE_TRACE("Position: {0}, {1}, {2}", vertex.Position.x, vertex.Position.y, vertex.Position.z); - PM_CORE_TRACE("Normal: {0}, {1}, {2}", vertex.Normal.x, vertex.Normal.y, vertex.Normal.z); - PM_CORE_TRACE("Binormal: {0}, {1}, {2}", vertex.Binormal.x, vertex.Binormal.y, vertex.Binormal.z); - PM_CORE_TRACE("Tangent: {0}, {1}, {2}", vertex.Tangent.x, vertex.Tangent.y, vertex.Tangent.z); - PM_CORE_TRACE("TexCoord: {0}, {1}", vertex.Texcoord.x, vertex.Texcoord.y); - PM_CORE_TRACE("--"); + for (size_t i = 0; i < m_AnimatedVertices.size(); i++) + { + auto& vertex = m_AnimatedVertices[i]; + PM_CORE_TRACE("Vertex: {0}", i); + PM_CORE_TRACE("Position: {0}, {1}, {2}", vertex.Position.x, vertex.Position.y, vertex.Position.z); + PM_CORE_TRACE("Normal: {0}, {1}, {2}", vertex.Normal.x, vertex.Normal.y, vertex.Normal.z); + PM_CORE_TRACE("Binormal: {0}, {1}, {2}", vertex.Binormal.x, vertex.Binormal.y, vertex.Binormal.z); + PM_CORE_TRACE("Tangent: {0}, {1}, {2}", vertex.Tangent.x, vertex.Tangent.y, vertex.Tangent.z); + PM_CORE_TRACE("TexCoord: {0}, {1}", vertex.Texcoord.x, vertex.Texcoord.y); + PM_CORE_TRACE("--"); + } + }else + { + for (size_t i = 0; i < m_StaticVertices.size(); i++) + { + auto& vertex = m_StaticVertices[i]; + PM_CORE_TRACE("Vertex: {0}", i); + PM_CORE_TRACE("Position: {0}, {1}, {2}", vertex.Position.x, vertex.Position.y, vertex.Position.z); + PM_CORE_TRACE("Normal: {0}, {1}, {2}", vertex.Normal.x, vertex.Normal.y, vertex.Normal.z); + PM_CORE_TRACE("Binormal: {0}, {1}, {2}", vertex.Binormal.x, vertex.Binormal.y, vertex.Binormal.z); + PM_CORE_TRACE("Tangent: {0}, {1}, {2}", vertex.Tangent.x, vertex.Tangent.y, vertex.Tangent.z); + PM_CORE_TRACE("TexCoord: {0}, {1}", vertex.Texcoord.x, vertex.Texcoord.y); + PM_CORE_TRACE("--"); + } } PM_CORE_TRACE("------------------------------------------------------"); } @@ -337,6 +427,25 @@ namespace Prism ReadNodeHierarchy(AnimationTime, pNode->mChildren[i], transform); } + void Mesh::TraverseNodes(aiNode* node, int level) + { + std::string levelText; + for (int i = 0; i < level; i++) + levelText += "-"; + PM_CORE_TRACE("{0}Node name: {1}", levelText, std::string(node->mName.data)); + for (uint32_t i = 0; i < node->mNumMeshes; i++) + { + uint32_t mesh = node->mMeshes[i]; + m_Submeshes[mesh].Transform = aiMatrix4x4ToGlm(node->mTransformation); + } + + for (uint32_t i = 0; i < node->mNumChildren; i++) + { + aiNode* child = node->mChildren[i]; + TraverseNodes(child, level + 1); + } + } + const aiNodeAnim* Mesh::FindNodeAnim(const aiAnimation* animation, const std::string& nodeName) { for (uint32_t i = 0; i < animation->mNumChannels; i++) diff --git a/Prism/src/Prism/Renderer/Mesh.h b/Prism/src/Prism/Renderer/Mesh.h index a9a7411..e21b197 100644 --- a/Prism/src/Prism/Renderer/Mesh.h +++ b/Prism/src/Prism/Renderer/Mesh.h @@ -8,6 +8,7 @@ #include #include "Buffer.h" +#include "Material.h" #include "Shader.h" #include "Prism/Core/TimeStep.h" @@ -30,6 +31,15 @@ namespace Prism glm::vec3 Tangent; glm::vec3 Binormal; glm::vec2 Texcoord; + }; + + struct AnimatedVertex + { + glm::vec3 Position; + glm::vec3 Normal; + glm::vec3 Tangent; + glm::vec3 Binormal; + glm::vec2 Texcoord; uint32_t IDs[4] = { 0, 0,0, 0 }; float Weights[4]{ 0.0f, 0.0f, 0.0f, 0.0f }; @@ -72,6 +82,8 @@ namespace Prism uint32_t BaseIndex; uint32_t MaterialIndex; uint32_t IndexCount; + + glm::mat4 Transform; }; class PRISM_API Mesh @@ -82,14 +94,18 @@ namespace Prism Mesh(const std::string& filename); ~Mesh(); - void Render(TimeStep deltaTime, Shader* shader); + void Render(TimeStep deltaTime, const Ref& materialInstance = Ref()); + void Render(TimeStep deltaTime, const glm::mat4& transform = glm::mat4(1.0f), const Ref& materialInstance = Ref()); void OnImGuiRender(); void DumpVertexBuffer(); + inline Ref GetMeshShader() { return m_MeshShader; } + inline Ref GetMaterial() { return m_Material; } inline const std::string& GetFilePath() const { return m_FilePath; } private: void BoneTransform(float time); void ReadNodeHierarchy(float AnimationTime, const aiNode* pNode, const glm::mat4& ParentTransform); + void TraverseNodes(aiNode* node, int level = 0); const aiNodeAnim* FindNodeAnim(const aiAnimation* animation, const std::string& nodeName); uint32_t FindPosition(float AnimationTime, const aiNodeAnim* pNodeAnim); @@ -112,13 +128,20 @@ namespace Prism std::unique_ptr m_VertexBuffer; std::unique_ptr m_IndexBuffer; - std::vector m_Vertices; + + std::vector m_StaticVertices; + std::vector m_AnimatedVertices; std::vector m_Indices; std::unordered_map m_BoneMapping; std::vector m_BoneTransforms; const aiScene* m_Scene; + // Material + Ref m_MeshShader; + Ref m_Material; + // Animation + bool m_IsAnimated = false; float m_AnimationTime = 0.0f; float m_WorldTime = 0.0f; float m_TimeMultiplier = 1.0f; diff --git a/Prism/src/Prism/Renderer/Renderer.cpp b/Prism/src/Prism/Renderer/Renderer.cpp index ac07405..f784cb0 100644 --- a/Prism/src/Prism/Renderer/Renderer.cpp +++ b/Prism/src/Prism/Renderer/Renderer.cpp @@ -41,7 +41,11 @@ namespace Prism void Renderer::Init() { + s_Instance->m_ShaderLibrary = std::make_unique(); PM_RENDER({ RendererAPI::Init(); }); + + GetShaderLibrary()->Load("assets/shaders/simplepbr_Static.glsl"); + GetShaderLibrary()->Load("assets/shaders/simplepbr_Anim.glsl"); } void Renderer::WaitAndRender() diff --git a/Prism/src/Prism/Renderer/Renderer.h b/Prism/src/Prism/Renderer/Renderer.h index 6f46ff0..bd35d61 100644 --- a/Prism/src/Prism/Renderer/Renderer.h +++ b/Prism/src/Prism/Renderer/Renderer.h @@ -5,6 +5,7 @@ #ifndef RENDERER_H #define RENDERER_H #include "RenderCommandQueue.h" +#include "Shader.h" #include "Prism/Core/Application.h" @@ -25,6 +26,8 @@ namespace Prism static void Init(); + static const Scope& GetShaderLibrary() { return Get().m_ShaderLibrary; } + static void* Submit(const RenderCommandFn func, const unsigned int size) { return s_Instance->m_CommandQueue.Allocate(func, size); @@ -35,6 +38,7 @@ namespace Prism private: static Renderer* s_Instance; + Scope m_ShaderLibrary; RenderCommandQueue m_CommandQueue; }; diff --git a/Prism/src/Prism/Renderer/Shader.cpp b/Prism/src/Prism/Renderer/Shader.cpp index 66f6140..0672846 100644 --- a/Prism/src/Prism/Renderer/Shader.cpp +++ b/Prism/src/Prism/Renderer/Shader.cpp @@ -9,16 +9,16 @@ namespace Prism { - std::vector Shader::s_AllShaders; + std::vector> Shader::s_AllShaders; - Shader* Shader::Create(const std::string& filepath) + Ref Shader::Create(const std::string& filepath) { - Shader* result = nullptr; + Ref result = nullptr; switch (RendererAPI::Current()) { case RendererAPIType::None: return nullptr; - case RendererAPIType::OpenGL: result = new OpenGLShader(filepath); + case RendererAPIType::OpenGL: result = CreateRef(filepath); } s_AllShaders.push_back(result); @@ -26,8 +26,43 @@ namespace Prism return result; } - std::vector& Shader::GetAllShaders() + std::vector>& Shader::GetAllShaders() { return s_AllShaders; } + + ShaderLibrary::ShaderLibrary() + { + } + + ShaderLibrary::~ShaderLibrary() + { + } + + void ShaderLibrary::Add(const Ref& shader) + { + auto& name = shader->GetName(); + PM_CORE_ASSERT(m_Shaders.find(name) == m_Shaders.end()); + m_Shaders[name] = shader; + } + + void ShaderLibrary::Load(const std::string& path) + { + auto shader = Ref(Shader::Create(path)); + auto& name = shader->GetName(); + PM_CORE_ASSERT(m_Shaders.find(name) == m_Shaders.end()); + m_Shaders[name] = shader; + } + + void ShaderLibrary::Load(const std::string& name, const std::string& path) + { + PM_CORE_ASSERT(m_Shaders.find(name) == m_Shaders.end()); + m_Shaders[name] = Ref(Shader::Create(path)); + } + + Ref& ShaderLibrary::Get(const std::string& name) + { + PM_CORE_ASSERT(m_Shaders.find(name) != m_Shaders.end()); + return m_Shaders[name]; + } } diff --git a/Prism/src/Prism/Renderer/Shader.h b/Prism/src/Prism/Renderer/Shader.h index 4181d51..97e58b9 100644 --- a/Prism/src/Prism/Renderer/Shader.h +++ b/Prism/src/Prism/Renderer/Shader.h @@ -122,11 +122,26 @@ namespace Prism virtual void AddShaderReloadedCallback(const ShaderReloadedCallback& callback) = 0; - static Shader* Create(const std::string& filepath); - static std::vector& GetAllShaders(); + static Ref Create(const std::string& filepath); + static std::vector>& GetAllShaders(); private: - static std::vector s_AllShaders; + static std::vector> s_AllShaders; + }; + + class ShaderLibrary + { + public: + ShaderLibrary(); + ~ShaderLibrary(); + + void Add(const Ref& shader); + void Load(const std::string& path); + void Load(const std::string& name, const std::string& path); + + Ref& Get(const std::string& name); + private: + std::unordered_map> m_Shaders; }; } diff --git a/Sandbox/Sandbox/Layer/DemoLayer.cpp b/Sandbox/Sandbox/Layer/DemoLayer.cpp index f7edefd..84a9984 100644 --- a/Sandbox/Sandbox/Layer/DemoLayer.cpp +++ b/Sandbox/Sandbox/Layer/DemoLayer.cpp @@ -111,13 +111,24 @@ DemoLayer::~DemoLayer() void DemoLayer::OnAttach() { - m_SimplePBRShader.reset(Prism::Shader::Create("assets/shaders/simplepbr.glsl")); - m_QuadShader.reset(Prism::Shader::Create("assets/shaders/quad.glsl")); - m_HDRShader.reset(Prism::Shader::Create("assets/shaders/hdr.glsl")); - m_GridShader.reset(Prism::Shader::Create("assets/shaders/Grid.glsl")); - m_Mesh.reset(new Prism::Mesh("assets/models/m1911/m1911.fbx")); - m_SphereMesh.reset(new Prism::Mesh("assets/models/Sphere1m.fbx")); - m_PlaneMesh.reset(new Prism::Mesh("assets/models/Plane1m.fbx")); + + m_Framebuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA16F)); + m_FinalPresentBuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA8)); + + m_QuadShader = Prism::Shader::Create("assets/shaders/quad.glsl"); + m_HDRShader= Prism::Shader::Create("assets/shaders/hdr.glsl"); + m_GridShader = Prism::Shader::Create("assets/shaders/Grid.glsl"); + + m_Mesh = Prism::CreateRef("assets/models/m1911/m1911.fbx"); + m_MeshMaterial = Prism::CreateRef(m_Mesh->GetMaterial()); + + m_SphereMesh = Prism::CreateRef("assets/models/Sphere1m.fbx"); + m_PlaneMesh = Prism::CreateRef("assets/models/Plane1m.fbx"); + + m_GridShader = Prism::Shader::Create("assets/shaders/Grid.glsl"); + m_GridMaterial = Prism::MaterialInstance::Create(Prism::Material::Create(m_GridShader)); + m_GridMaterial->Set("u_Scale", m_GridScale); + m_GridMaterial->Set("u_Res", m_GridSize); // Editor m_CheckerboardTex.reset(Prism::Texture2D::Create("assets/editor/Checkerboard.tga")); @@ -127,16 +138,12 @@ void DemoLayer::OnAttach() 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)); - - m_PBRMaterial.reset(new Prism::Material(m_SimplePBRShader)); float x = -4.0f; float roughness = 0.0f; for (int i = 0; i < 8; i++) { - Prism::Ref mi(new Prism::MaterialInstance(m_PBRMaterial)); + Prism::Ref mi = Prism::CreateRef(m_SphereMesh->GetMaterial()); mi->Set("u_Metalness", 1.0f); mi->Set("u_Roughness", roughness); mi->Set("u_ModelMatrix", glm::translate(glm::mat4(1.0f), glm::vec3(x, 0.0f, 0.0f))); @@ -149,7 +156,7 @@ void DemoLayer::OnAttach() roughness = 0.0f; for (int i = 0; i < 8; i++) { - Prism::Ref mi(new Prism::MaterialInstance(m_PBRMaterial)); + Prism::Ref mi = Prism::CreateRef(m_SphereMesh->GetMaterial()); mi->Set("u_Metalness", 0.0f); mi->Set("u_Roughness", roughness); mi->Set("u_ModelMatrix", translate(glm::mat4(1.0f), glm::vec3(x, 1.2f, 0.0f))); @@ -212,10 +219,6 @@ void DemoLayer::OnUpdate(const Prism::TimeStep deltaTime) m_Framebuffer->Bind(); Renderer::Clear(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]); - Prism::UniformBufferDeclaration quadShaderUB; - quadShaderUB.Push("u_InverseVP", inverse(viewProjection)); - m_QuadShader->UploadUniformBuffer(quadShaderUB); - m_QuadShader->Bind(); m_QuadShader->SetMat4("u_InverseVP", inverse(viewProjection)); m_EnvironmentCubeMap->Bind(0); @@ -224,72 +227,72 @@ void DemoLayer::OnUpdate(const Prism::TimeStep deltaTime) Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false); - m_PBRMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color); - m_PBRMaterial->Set("u_Metalness", m_MetalnessInput.Value); - m_PBRMaterial->Set("u_Roughness", m_RoughnessInput.Value); - m_PBRMaterial->Set("u_ViewProjectionMatrix", viewProjection); - m_PBRMaterial->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale))); - m_PBRMaterial->Set("lights", m_Light); - m_PBRMaterial->Set("u_CameraPosition", m_Camera.GetPosition()); - m_PBRMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f); - m_PBRMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f); - m_PBRMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f); - m_PBRMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f); - m_PBRMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f); - m_PBRMaterial->Set("u_EnvMapRotation", m_EnvMapRotation); + m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color); + m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value); + m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value); + m_MeshMaterial->Set("u_ViewProjectionMatrix", viewProjection); + m_MeshMaterial->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale))); + m_MeshMaterial->Set("lights", m_Light); + m_MeshMaterial->Set("u_CameraPosition", m_Camera.GetPosition()); + m_MeshMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f); + m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation); - m_PBRMaterial->Set("u_EnvRadianceTex", m_EnvironmentCubeMap); - m_PBRMaterial->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance); - m_PBRMaterial->Set("u_BRDFLUTTexture", m_BRDFLUT); - /* - Prism::UniformBufferDeclaration 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_MeshMaterial->Set("u_EnvRadianceTex", m_EnvironmentCubeMap); + m_MeshMaterial->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance); + m_MeshMaterial->Set("u_BRDFLUTTexture", m_BRDFLUT); + + m_SphereMesh->GetMaterial()->Set("u_AlbedoColor", m_AlbedoInput.Color); + m_SphereMesh->GetMaterial()->Set("u_Metalness", m_MetalnessInput.Value); + m_SphereMesh->GetMaterial()->Set("u_Roughness", m_RoughnessInput.Value); + m_SphereMesh->GetMaterial()->Set("u_ViewProjectionMatrix", viewProjection); + m_SphereMesh->GetMaterial()->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale))); + m_SphereMesh->GetMaterial()->Set("lights", m_Light); + m_SphereMesh->GetMaterial()->Set("u_CameraPosition", m_Camera.GetPosition()); + m_SphereMesh->GetMaterial()->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f); + m_SphereMesh->GetMaterial()->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f); + m_SphereMesh->GetMaterial()->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f); + m_SphereMesh->GetMaterial()->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f); + m_SphereMesh->GetMaterial()->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f); + m_SphereMesh->GetMaterial()->Set("u_EnvMapRotation", m_EnvMapRotation); + m_SphereMesh->GetMaterial()->Set("u_EnvRadianceTex", m_EnvironmentCubeMap); + m_SphereMesh->GetMaterial()->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance); + m_SphereMesh->GetMaterial()->Set("u_BRDFLUTTexture", m_BRDFLUT); - m_EnvironmentCubeMap->Bind(10); - m_EnvironmentIrradiance->Bind(11); - m_BRDFLUT->Bind(15); - m_SimplePBRShader->Bind(); - */ if (m_AlbedoInput.TextureMap) - m_PBRMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap); + m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap); if (m_NormalInput.TextureMap) - m_PBRMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap); + m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap); if (m_MetalnessInput.TextureMap) - m_PBRMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap); + m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap); if (m_RoughnessInput.TextureMap) - m_PBRMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap); + m_MeshMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap); if (m_Scene == Scene::Spheres) { // Metals for (int i = 0; i < 8; i++) { - + m_SphereMesh->Render(deltaTime, glm::mat4(1.0f), m_MetalSphereMaterialInstances[i]); + /* m_MetalSphereMaterialInstances[i]->Bind(); m_SphereMesh->Render(deltaTime, m_SimplePBRShader.get()); + */ } // Dielectrics for (int i = 0; i < 8; i++) { + m_SphereMesh->Render(deltaTime, glm::mat4(1.0f), m_DielectricSphereMaterialInstances[i]); + /* m_DielectricSphereMaterialInstances[i]->Bind(); m_SphereMesh->Render(deltaTime, m_SimplePBRShader.get()); + */ } } @@ -297,16 +300,13 @@ void DemoLayer::OnUpdate(const Prism::TimeStep deltaTime) { if (m_Mesh) { - m_PBRMaterial->Bind(); - m_Mesh->Render(deltaTime, m_SimplePBRShader.get()); + m_Mesh->Render(deltaTime, scale(mat4(1.0f), vec3(m_MeshScale)), m_MeshMaterial); } } - m_GridShader->Bind(); - m_GridShader->SetMat4("u_MVP", viewProjection * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f))); - m_GridShader->SetFloat("u_Scale", m_GridScale); - m_GridShader->SetFloat("u_Res", m_GridSize); - m_PlaneMesh->Render(deltaTime, m_GridShader.get()); + m_GridMaterial->Set("u_MVP", viewProjection * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f))); + m_PlaneMesh->Render(deltaTime, m_GridMaterial); + m_Framebuffer->Unbind(); m_FinalPresentBuffer->Bind(); @@ -436,206 +436,216 @@ void DemoLayer::OnImGuiRender() #endif - // Editor Panel ------------------------------------------------------------------------------ - ImGui::Begin("Model"); - ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres); - ImGui::SameLine(); - ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model); + // Editor Panel ------------------------------------------------------------------------------ + ImGui::Begin("Model"); + ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres); + ImGui::SameLine(); + ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model); - ImGui::Begin("Environment"); + ImGui::Begin("Environment"); - ImGui::Columns(2); - ImGui::AlignTextToFramePadding(); + ImGui::Columns(2); + ImGui::AlignTextToFramePadding(); - Property("Light Direction", m_Light.Direction); - Property("Light Radiance", m_Light.Radiance, PropertyFlag::ColorProperty); - Property("Light Multiplier", m_LightMultiplier, 0.0f, 5.0f); - Property("Exposure", m_Exposure, 0.0f, 5.0f); + Property("Light Direction", m_Light.Direction); + Property("Light Radiance", m_Light.Radiance, PropertyFlag::ColorProperty); + Property("Light Multiplier", m_LightMultiplier, 0.0f, 5.0f); + Property("Exposure", m_Exposure, 0.0f, 5.0f); - Property("Radiance Prefiltering", m_RadiancePrefilter); - Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f); + Property("Radiance Prefiltering", m_RadiancePrefilter); + Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f); - ImGui::Columns(1); + ImGui::Columns(1); - ImGui::End(); + ImGui::End(); - ImGui::Separator(); + 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")) { - 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)); - } + std::string filename = Prism::Application::Get().OpenFile(""); + if (filename != "") + m_Mesh.reset(new Prism::Mesh(filename)); } - ImGui::Separator(); + } + ImGui::Separator(); - // Textures ------------------------------------------------------------------------------ + // Textures ------------------------------------------------------------------------------ + { + // Albedo + if (ImGui::CollapsingHeader("Albedo", nullptr, ImGuiTreeNodeFlags_DefaultOpen)) { - // Albedo - if (ImGui::CollapsingHeader("Albedo", nullptr, ImGuiTreeNodeFlags_DefaultOpen)) + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); + ImGui::Image((ImTextureRef)(m_AlbedoInput.TextureMap ? m_AlbedoInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64)); + ImGui::PopStyleVar(); + if (ImGui::IsItemHovered()) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); - ImGui::Image((ImTextureRef)(m_AlbedoInput.TextureMap ? m_AlbedoInput.TextureMap->GetRendererID() : m_CheckerboardTex->GetRendererID()), ImVec2(64, 64)); - ImGui::PopStyleVar(); - if (ImGui::IsItemHovered()) + if (m_AlbedoInput.TextureMap) { - if (m_AlbedoInput.TextureMap) - { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted(m_AlbedoInput.TextureMap->GetPath().c_str()); - ImGui::PopTextWrapPos(); - ImGui::Image((ImTextureRef)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::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(m_AlbedoInput.TextureMap->GetPath().c_str()); + ImGui::PopTextWrapPos(); + ImGui::Image((ImTextureRef)m_AlbedoInput.TextureMap->GetRendererID(), ImVec2(384, 384)); + ImGui::EndTooltip(); } - ImGui::SameLine(); - ImGui::BeginGroup(); - ImGui::Checkbox("Use##AlbedoMap", &m_AlbedoInput.UseTexture); - if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB)) + if (ImGui::IsItemClicked()) { - 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((ImTextureRef)(m_NormalInput.TextureMap ? m_NormalInput.TextureMap->GetRendererID() : 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((ImTextureRef)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((ImTextureRef)(m_MetalnessInput.TextureMap ? m_MetalnessInput.TextureMap->GetRendererID() : 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((ImTextureRef)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((ImTextureRef)(m_RoughnessInput.TextureMap ? m_RoughnessInput.TextureMap->GetRendererID() : 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((ImTextureRef)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); - } - } - - if (ImGui::TreeNode("Shaders")) - { - auto& shaders = Prism::Shader::GetAllShaders(); - 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(); + std::string filename = Prism::Application::Get().OpenFile(""); + if (filename != "") + m_AlbedoInput.TextureMap.reset(Prism::Texture2D::Create(filename, m_AlbedoInput.SRGB)); } } - ImGui::TreePop(); + 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((ImTextureRef)(m_NormalInput.TextureMap ? m_NormalInput.TextureMap->GetRendererID() : 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((ImTextureRef)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((ImTextureRef)(m_MetalnessInput.TextureMap ? m_MetalnessInput.TextureMap->GetRendererID() : 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((ImTextureRef)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((ImTextureRef)(m_RoughnessInput.TextureMap ? m_RoughnessInput.TextureMap->GetRendererID() : 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((ImTextureRef)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(); + if (ImGui::TreeNode("Shaders")) + { + auto& shaders = Prism::Shader::GetAllShaders(); + 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::End(); + ImGui::Separator(); - 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((ImTextureRef)m_FinalPresentBuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 }); - // ImGui::Image((void*)m_Framebuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 }); - ImGui::End(); - ImGui::PopStyleVar(); + 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((ImTextureRef)m_FinalPresentBuffer->GetColorAttachmentRendererID(), viewportSize, { 0, 1 }, { 1, 0 }); + ImGui::End(); + ImGui::PopStyleVar(); + + ImGui::Begin("Log"); + const auto& cameraPos = m_Camera.GetPosition(); + ImGui::Text("cameraPos: (%.2f, %.2f, %.2f)", cameraPos.x, cameraPos.y, cameraPos.z); + + const auto& Direct = m_Camera.GetForwardDirection(); + ImGui::Text("forward Vec: (%.2f, %.2f, %.2f)", Direct.x, Direct.y, Direct.z); + + const auto& distance = m_Camera.GetDistance(); + ImGui::Text("distance: %.3f", distance); + ImGui::End(); if (m_Mesh) m_Mesh->OnImGuiRender(); diff --git a/Sandbox/Sandbox/Layer/DemoLayer.h b/Sandbox/Sandbox/Layer/DemoLayer.h index 44f586e..7ea0021 100644 --- a/Sandbox/Sandbox/Layer/DemoLayer.h +++ b/Sandbox/Sandbox/Layer/DemoLayer.h @@ -26,15 +26,16 @@ public: private: float m_ClearColor[4]; - Prism::Ref m_SimplePBRShader; - Prism::Scope m_QuadShader; - Prism::Scope m_HDRShader; - Prism::Scope m_GridShader; - Prism::Scope m_Mesh; - Prism::Scope m_SphereMesh, m_PlaneMesh; + Prism::Ref m_QuadShader; + Prism::Ref m_HDRShader; + Prism::Ref m_GridShader; + Prism::Ref m_Mesh; + Prism::Ref m_SphereMesh, m_PlaneMesh; Prism::Ref m_BRDFLUT; - Prism::Ref m_PBRMaterial; + Prism::Ref m_MeshMaterial; + Prism::Ref m_GridMaterial; + std::vector> m_MetalSphereMaterialInstances; std::vector> m_DielectricSphereMaterialInstances; diff --git a/Sandbox/Sandbox/Layer/TestLayer.cpp b/Sandbox/Sandbox/Layer/TestLayer.cpp index 94e2419..2ddc255 100644 --- a/Sandbox/Sandbox/Layer/TestLayer.cpp +++ b/Sandbox/Sandbox/Layer/TestLayer.cpp @@ -174,9 +174,9 @@ void TestLayer::OnAttach() 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_SkyboxShader = Prism::Shader::Create("assets/shaders/quad.glsl"); + m_Shader = Prism::Shader::Create("assets/shaders/demo.glsl"); + m_HDRShader = Prism::Shader::Create("assets/shaders/hdr.glsl"); m_Mesh = std::make_unique("assets/meshes/cerberus.fbx"); } @@ -210,7 +210,7 @@ void TestLayer::OnUpdate(Prism::TimeStep deltaTime) m_Shader->Bind(); - m_Mesh->Render(deltaTime, m_Shader.get()); + // m_Mesh->Render(deltaTime, m_Shader); // m_VertexBuffer->Bind(); // m_IndexBuffer->Bind(); diff --git a/Sandbox/Sandbox/Layer/TestLayer.h b/Sandbox/Sandbox/Layer/TestLayer.h index 01ee54f..1762016 100644 --- a/Sandbox/Sandbox/Layer/TestLayer.h +++ b/Sandbox/Sandbox/Layer/TestLayer.h @@ -28,17 +28,17 @@ 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 m_FrameBuffer, m_FinalPresentBuffer; - std::unique_ptr m_VertexBuffer; - std::unique_ptr m_IndexBuffer; + Prism::Ref m_FrameBuffer, m_FinalPresentBuffer; + Prism::Ref m_VertexBuffer; + Prism::Ref m_IndexBuffer; - std::unique_ptr m_SkyBoxTextureCube; + Prism::Ref m_SkyBoxTextureCube; - std::unique_ptr m_SkyboxShader; - std::unique_ptr m_Shader; - std::unique_ptr m_HDRShader; - std::unique_ptr m_Mesh; + Prism::Ref m_SkyboxShader; + Prism::Ref m_Shader; + Prism::Ref m_HDRShader; + Prism::Ref m_Mesh; Prism::Camera m_Camera; diff --git a/Sandbox/Sandbox/Sandbox.cpp b/Sandbox/Sandbox/Sandbox.cpp index fb5fa70..60de5be 100644 --- a/Sandbox/Sandbox/Sandbox.cpp +++ b/Sandbox/Sandbox/Sandbox.cpp @@ -18,8 +18,8 @@ public: virtual void OnInit() override { - PushLayer(new TestLayer()); - // PushLayer(new DemoLayer()); + // PushLayer(new TestLayer()); + PushLayer(new DemoLayer()); } }; diff --git a/Sandbox/assets/shaders/Grid.glsl b/Sandbox/assets/shaders/Grid.glsl index fa2ced0..c6885bb 100644 --- a/Sandbox/assets/shaders/Grid.glsl +++ b/Sandbox/assets/shaders/Grid.glsl @@ -23,7 +23,6 @@ void main() layout(location = 0) out vec4 color; -uniform sampler2D u_Texture; uniform float u_Scale; uniform float u_Res; diff --git a/Sandbox/assets/shaders/simplepbr.glsl b/Sandbox/assets/shaders/simplepbr_Anim.glsl similarity index 100% rename from Sandbox/assets/shaders/simplepbr.glsl rename to Sandbox/assets/shaders/simplepbr_Anim.glsl diff --git a/Sandbox/assets/shaders/simplepbr_Static.glsl b/Sandbox/assets/shaders/simplepbr_Static.glsl new file mode 100644 index 0000000..85709e0 --- /dev/null +++ b/Sandbox/assets/shaders/simplepbr_Static.glsl @@ -0,0 +1,321 @@ +// ----------------------------- +// -- 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; + vec3 Binormal; +} vs_Output; + +void main() +{ + vs_Output.WorldPosition = vec3(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); + vs_Output.Binormal = a_Binormal; + + 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; + vec3 Binormal; +} 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); +}