diff --git a/Editor/Editor/EditorLayer.cpp b/Editor/Editor/EditorLayer.cpp index 081c3cb..8f0584f 100644 --- a/Editor/Editor/EditorLayer.cpp +++ b/Editor/Editor/EditorLayer.cpp @@ -582,6 +582,20 @@ namespace Prism UI::PropertySlider("Exposure", m_EditorCamera.GetExposure(), 0.0f, 5.0f); + ImGui::Separator(); + float near = m_EditorCamera.GetNear(); + float far = m_EditorCamera.GetFar(); + + if (UI::Property("Near", near)) + { + m_EditorCamera.SetNearFar(near, far); + } + if (UI::Property("Far", far)) + { + m_EditorCamera.SetNearFar(near, far); + } + + ImGui::Separator(); float physics2DGravity = m_EditorScene->GetPhysics2DGravity(); if (UI::Property("2D World Gravity", physics2DGravity, -100.0f, 100.0f)) @@ -664,7 +678,6 @@ namespace Prism { SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); m_EditorScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); - m_EditorCamera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 1000.0f)); m_EditorCamera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 }); diff --git a/Editor/assets/shaders/EnvironmentMipFilter.glsl b/Editor/assets/shaders/EnvironmentMipFilter.glsl index 26d4d5b..5c9d065 100644 --- a/Editor/assets/shaders/EnvironmentMipFilter.glsl +++ b/Editor/assets/shaders/EnvironmentMipFilter.glsl @@ -107,16 +107,16 @@ void main(void) if(gl_GlobalInvocationID.x >= outputSize.x || gl_GlobalInvocationID.y >= outputSize.y) { return; } - + // Solid angle associated with a single cubemap texel at zero mipmap level. // This will come in handy for importance sampling below. vec2 inputSize = vec2(textureSize(inputTexture, 0)); float wt = 4.0 * PI / (6 * inputSize.x * inputSize.y); - + // Approximation: Assume zero viewing angle (isotropic reflections). vec3 N = GetCubeMapTexCoord(); vec3 Lo = N; - + vec3 S, T; computeBasisVectors(N, S, T); diff --git a/Prism/src/Prism/Editor/EditorCamera.cpp b/Prism/src/Prism/Editor/EditorCamera.cpp index 7e6422b..7b5d5db 100644 --- a/Prism/src/Prism/Editor/EditorCamera.cpp +++ b/Prism/src/Prism/Editor/EditorCamera.cpp @@ -276,5 +276,17 @@ namespace Prism return speed; } - -} \ No newline at end of file + void EditorCamera::UpdateProjectionMatrix() + { + float aspect = (float)m_ViewportWidth / (float)m_ViewportHeight; + glm::mat4 proj; + if (m_IsPerspective) { + proj = glm::perspective(glm::radians(m_FOV), aspect, m_Near, m_Far); + } else { + // 正交投影示例 + float size = 10.0f; + proj = glm::ortho(-size * aspect, size * aspect, -size, size, m_Near, m_Far); + } + SetProjectionMatrix(proj); + } +} diff --git a/Prism/src/Prism/Editor/EditorCamera.h b/Prism/src/Prism/Editor/EditorCamera.h index 79c47ac..e0bc924 100644 --- a/Prism/src/Prism/Editor/EditorCamera.h +++ b/Prism/src/Prism/Editor/EditorCamera.h @@ -30,6 +30,9 @@ namespace Prism inline void SetDistance(float distance) { m_Distance = distance; } inline void SetProjectionMatrix(const glm::mat4& projectionMatrix) { m_ProjectionMatrix = projectionMatrix; } + void SetNearFar(const float near = 0.1f, const float far = 1000.f) { m_Near = near; m_Far = far; UpdateProjectionMatrix(); } + float GetNear() const { return m_Near; } + float GetFar() const { return m_Far; } const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; } const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; } @@ -48,7 +51,7 @@ namespace Prism void OnImGuiRender(); public: - inline void SetViewportSize(const uint32_t width, const uint32_t height) { m_ViewportWidth = width; m_ViewportHeight = height; } + inline void SetViewportSize(const uint32_t width, const uint32_t height) { m_ViewportWidth = width; m_ViewportHeight = height; UpdateProjectionMatrix(); } private: void UpdateCameraView(); @@ -62,7 +65,15 @@ namespace Prism std::pair PanSpeed() const; float RotationSpeed() const; float ZoomSpeed() const; + + void UpdateProjectionMatrix(); + private: + float m_Near = 0.1f; + float m_Far = 1000.0f; + float m_FOV = 45.0f; + bool m_IsPerspective = true; + glm::mat4 m_ViewMatrix; glm::vec3 m_Position, m_Rotation, m_FocalPoint; diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp index 812472f..a21c0de 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.cpp @@ -18,6 +18,7 @@ namespace Prism case TextureFormat::RGB: return GL_RGB; case TextureFormat::RGBA: return GL_RGBA; case TextureFormat::RGBA16F: return GL_RGBA16F; + case TextureFormat::RG16F: return GL_RG16F; } return 0; } @@ -27,6 +28,7 @@ namespace Prism case TextureFormat::RGB: return GL_RGB8; case TextureFormat::RGBA: return GL_RGBA8; case TextureFormat::RGBA16F: return GL_RGBA16F; + case TextureFormat::RG16F: return GL_RG16F; default: return 0; } } @@ -35,7 +37,8 @@ namespace Prism switch (format) { case TextureFormat::RGB: return GL_RGB; case TextureFormat::RGBA: return GL_RGBA; - case TextureFormat::RGBA16F: return GL_RGBA; // 根据实际情况调整 + case TextureFormat::RGBA16F: return GL_RGBA; + case TextureFormat::RG16F: return GL_RG; default: return 0; } } @@ -131,71 +134,114 @@ namespace Prism } - OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb) + OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb, bool isLUT) : m_FilePath(path) { - int width, height, channels; - if (stbi_is_hdr(path.c_str())) + + if (isLUT) { - PM_CORE_INFO("Loading HDR texture {0}, srgb={1}", path, srgb); - m_ImageData.Data = (byte*)stbi_loadf(path.c_str(), &width, &height, &channels, 0); - m_IsHDR = true; - m_Format = TextureFormat::RGBA16F; - } - else + int width, height, channels; + float* data = stbi_loadf(path.c_str(), &width, &height, &channels, 2); + if (!data) + { + PM_CORE_ERROR("Failed to load BRDF LUT: {0}", path); + return; + } + + m_Loaded = true; + m_Width = width; + m_Height = height; + m_Format = TextureFormat::RG16F; + m_IsHDR = true; + m_ImageData.Data = (byte*)data; + + Ref instance = this; + Renderer::Submit([instance, width, height]() mutable + { + glCreateTextures(GL_TEXTURE_2D, 1, &instance->m_RendererID); + + // 内部格式:双通道 16 位浮点 + glTextureStorage2D(instance->m_RendererID, 1, GL_RG16F, width, height); + + // 包裹模式必须为 CLAMP_TO_EDGE,防止 LUT 边缘插值错误 + glTextureParameteri(instance->m_RendererID, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTextureParameteri(instance->m_RendererID, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // LUT 不需要 mipmap,使用线性过滤即可 + glTextureParameteri(instance->m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTextureParameteri(instance->m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // 上传数据:紧密排列的 RG 浮点数组 + glTextureSubImage2D(instance->m_RendererID, 0, 0, 0, + width, height, GL_RG, GL_FLOAT, instance->m_ImageData.Data); + + stbi_image_free(instance->m_ImageData.Data); + }); + }else { - PM_CORE_INFO("Loading texture {0}, srgb={1}", path, srgb); - m_ImageData.Data = stbi_load(path.c_str(), &width, &height, &channels, srgb ? STBI_rgb : STBI_rgb_alpha); - if (!m_ImageData.Data) PM_CORE_ERROR("Could not read image file: {0}", path); - m_Format = TextureFormat::RGBA; + int width, height, channels; + if (stbi_is_hdr(path.c_str())) + { + PM_CORE_INFO("Loading HDR texture {0}, srgb={1}", path, srgb); + m_ImageData.Data = (byte*)stbi_loadf(path.c_str(), &width, &height, &channels, 0); + m_IsHDR = true; + m_Format = TextureFormat::RGBA16F; + } + else + { + PM_CORE_INFO("Loading texture {0}, srgb={1}", path, srgb); + m_ImageData.Data = stbi_load(path.c_str(), &width, &height, &channels, srgb ? STBI_rgb : STBI_rgb_alpha); + if (!m_ImageData.Data) PM_CORE_ERROR("Could not read image file: {0}", path); + m_Format = TextureFormat::RGBA; + } + + if (!m_ImageData.Data) + return; + m_Loaded = true; + + m_Width = width; + m_Height = height; + + Ref instance = this; + Renderer::Submit([instance, srgb]() mutable { + // TODO: Consolidate properly + if (srgb) + { + glCreateTextures(GL_TEXTURE_2D, 1, &instance->m_RendererID); + const auto levels = (GLint)CalculateMipMapCount(instance->m_Width, instance->m_Height); + glTextureStorage2D(instance->m_RendererID, levels, GL_SRGB8, (GLint)instance->m_Width, (GLint)instance->m_Height); + glTextureParameteri(instance->m_RendererID, GL_TEXTURE_MIN_FILTER, levels > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); + glTextureParameteri(instance->m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTextureSubImage2D(instance->m_RendererID, 0, 0, 0, (GLint)instance->m_Width, (GLint)instance->m_Height, GL_RGB, GL_UNSIGNED_BYTE, instance->m_ImageData.Data); + glGenerateTextureMipmap(instance->m_RendererID); + } + else + { + glGenTextures(1, &instance->m_RendererID); + glBindTexture(GL_TEXTURE_2D, instance->m_RendererID); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + const GLint wrap = instance->m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, wrap); + + GLenum internalFormat = PrismToOpenGLTextureFormat(instance->m_Format); + GLenum format = srgb ? GL_SRGB8 : (instance->m_IsHDR ? GL_RGB : PrismToOpenGLTextureFormat(instance->m_Format)); // HDR = GL_RGB for now + GLenum type = internalFormat == GL_RGBA16F ? GL_FLOAT : GL_UNSIGNED_BYTE; + glTexImage2D(GL_TEXTURE_2D, 0, (GLint)internalFormat, (GLint)instance->m_Width, (GLint)instance->m_Height, 0, format, type, instance->m_ImageData.Data); + + glGenerateMipmap(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, 0); + } + stbi_image_free(instance->m_ImageData.Data); + }); } - - if (!m_ImageData.Data) - return; - m_Loaded = true; - - m_Width = width; - m_Height = height; - - Ref instance = this; - Renderer::Submit([instance, srgb]() mutable { - // TODO: Consolidate properly - if (srgb) - { - glCreateTextures(GL_TEXTURE_2D, 1, &instance->m_RendererID); - const auto levels = (GLint)CalculateMipMapCount(instance->m_Width, instance->m_Height); - glTextureStorage2D(instance->m_RendererID, levels, GL_SRGB8, (GLint)instance->m_Width, (GLint)instance->m_Height); - glTextureParameteri(instance->m_RendererID, GL_TEXTURE_MIN_FILTER, levels > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); - glTextureParameteri(instance->m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTextureSubImage2D(instance->m_RendererID, 0, 0, 0, (GLint)instance->m_Width, (GLint)instance->m_Height, GL_RGB, GL_UNSIGNED_BYTE, instance->m_ImageData.Data); - glGenerateTextureMipmap(instance->m_RendererID); - } - else - { - glGenTextures(1, &instance->m_RendererID); - glBindTexture(GL_TEXTURE_2D, instance->m_RendererID); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - const GLint wrap = instance->m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT; - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, wrap); - - GLenum internalFormat = PrismToOpenGLTextureFormat(instance->m_Format); - GLenum format = srgb ? GL_SRGB8 : (instance->m_IsHDR ? GL_RGB : PrismToOpenGLTextureFormat(instance->m_Format)); // HDR = GL_RGB for now - GLenum type = internalFormat == GL_RGBA16F ? GL_FLOAT : GL_UNSIGNED_BYTE; - glTexImage2D(GL_TEXTURE_2D, 0, (GLint)internalFormat, (GLint)instance->m_Width, (GLint)instance->m_Height, 0, format, type, instance->m_ImageData.Data); - - glGenerateMipmap(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, 0); - } - stbi_image_free(instance->m_ImageData.Data); - }); } OpenGLTexture2D::~OpenGLTexture2D() diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h index d2d9669..b57749e 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLTexture.h @@ -15,7 +15,7 @@ namespace Prism public: OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, TextureWrap wrap); OpenGLTexture2D(TextureFormat format, uint32_t width, uint32_t height, const void* data, TextureWrap wrap = TextureWrap::Clamp); - OpenGLTexture2D(const std::string& path, bool srgb); + OpenGLTexture2D(const std::string& path, bool srgb, bool isLUT = false); virtual ~OpenGLTexture2D(); virtual void Bind(uint32_t slot = 0) const override; diff --git a/Prism/src/Prism/Renderer/Mesh.cpp b/Prism/src/Prism/Renderer/Mesh.cpp index 8fcfa11..f98efd2 100644 --- a/Prism/src/Prism/Renderer/Mesh.cpp +++ b/Prism/src/Prism/Renderer/Mesh.cpp @@ -288,13 +288,15 @@ namespace Prism PM_CORE_TRACE("COLOR = {0}, {1}, {2}", aiColor.r, aiColor.g, aiColor.b); float shininess, metalness; + if (aiMaterial->Get(AI_MATKEY_SHININESS, shininess) != aiReturn_SUCCESS) shininess = 0.0f; // Default value - aiMaterial->Get(AI_MATKEY_REFLECTIVITY, metalness); - if (aiMaterial->Get(AI_MATKEY_REFLECTIVITY, metalness) != aiReturn_SUCCESS) + float roughness = shininess > 0.0f ? glm::sqrt(2.0f / (shininess + 2.0f)) : 0.7f; // 或使用你的公式 + roughness = glm::clamp(roughness, 0.0f, 1.0f); + + if (aiMaterial->Get(AI_MATKEY_METALLIC_FACTOR, metalness) != aiReturn_SUCCESS) metalness = 0.0f; - float roughness = 1.0f - glm::sqrt(shininess / 100.0f); PM_MESH_LOG(" COLOR = {0}, {1}, {2}", aiColor.r, aiColor.g, aiColor.b); PM_MESH_LOG(" ROUGHNESS = {0}", roughness); bool hasAlbedoMap = aiMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &aiTexPath) == AI_SUCCESS; @@ -388,38 +390,6 @@ namespace Prism mi->Set("u_Roughness", roughness); } - -#if 0 - // Metalness map - // mi->Set("u_Metalness", 0.0f); - // mi->Set("u_MetalnessTexToggle", 0.0f); - if (aiMaterial->Get("$raw.ReflectionFactor|file", aiPTI_String, 0, aiTexPath) == AI_SUCCESS) - { - // TODO: Temp - this should be handled by Prism's filesystem - std::filesystem::path path = filename; - auto parentPath = path.parent_path(); - parentPath /= std::string(aiTexPath.data); - std::string texturePath = parentPath.string(); - - auto texture = Texture2D::Create(texturePath); - if (texture->Loaded()) - { - PM_MESH_LOG(" Metalness map path = {0}", texturePath); - mi->Set("u_MetalnessTexture", texture); - mi->Set("u_MetalnessTexToggle", 1.0f); - } - else - { - PM_CORE_ERROR("Could not load texture: {0}", texturePath); - } - } - else - { - PM_MESH_LOG(" no metalness texture"); - mi->Set("u_Metalness", metalness); - } - continue; -#endif bool metalnessTextureFound = false; for (uint32_t i = 0; i < aiMaterial->mNumProperties; i++) diff --git a/Prism/src/Prism/Renderer/Renderer3D.cpp b/Prism/src/Prism/Renderer/Renderer3D.cpp index e8dea0a..494c494 100644 --- a/Prism/src/Prism/Renderer/Renderer3D.cpp +++ b/Prism/src/Prism/Renderer/Renderer3D.cpp @@ -242,7 +242,7 @@ namespace Prism ///////////////////////////////////////////// s_Data.CompositeShader = Shader::Create("assets/shaders/SceneComposite.glsl"); - s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga"); + s_Data.BRDFLUT = Texture2D::Create("assets/textures/BRDF_LUT.tga", false, true); // Grid // const auto gridShader = Shader::Create("assets/shaders/Grid.glsl"); @@ -649,6 +649,7 @@ namespace Prism const bool collider = !s_Data.ColliderDrawList.empty(); auto cmd = Renderer::GetCommandBuffer(); + /* if (outline) { Renderer::Submit([cmd]() @@ -659,9 +660,11 @@ namespace Prism cmd->SetStencilMask(0xFF); }); } + */ Renderer::BeginRenderPass(s_Data.GeoPass); + /* if (outline) { Renderer::Submit([cmd]() @@ -669,6 +672,7 @@ namespace Prism cmd->SetStencilMask(0); }); } + */ const auto& sceneCamera = s_Data.SceneData.SceneCamera; @@ -852,6 +856,7 @@ namespace Prism } + /* if (outline) { Renderer::Submit([cmd]() @@ -893,6 +898,7 @@ namespace Prism cmd->SetStencilTest(false); }); } + */ if (collider) { diff --git a/Prism/src/Prism/Renderer/Texture.cpp b/Prism/src/Prism/Renderer/Texture.cpp index e84aeb8..d0c1208 100644 --- a/Prism/src/Prism/Renderer/Texture.cpp +++ b/Prism/src/Prism/Renderer/Texture.cpp @@ -49,12 +49,12 @@ namespace Prism } - Ref Texture2D::Create(const std::string& path, bool srgb) + Ref Texture2D::Create(const std::string& path, bool srgb, bool isLUT) { switch (RendererAPI::Current()) { case RendererAPIType::None: return nullptr; - case RendererAPIType::OpenGL: return Ref::Create(path, srgb); + case RendererAPIType::OpenGL: return Ref::Create(path, srgb, isLUT); } return nullptr; } diff --git a/Prism/src/Prism/Renderer/Texture.h b/Prism/src/Prism/Renderer/Texture.h index 02f331e..6d0053c 100644 --- a/Prism/src/Prism/Renderer/Texture.h +++ b/Prism/src/Prism/Renderer/Texture.h @@ -19,6 +19,7 @@ namespace Prism RGB = 1, RGBA = 2, RGBA16F = 3, + RG16F = 4, }; enum class TextureWrap @@ -54,7 +55,7 @@ namespace Prism public: static Ref Create(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap = TextureWrap::Clamp); static Ref Create(TextureFormat format, unsigned int width, unsigned int height, const void* data, TextureWrap wrap = TextureWrap::Clamp); - static Ref Create(const std::string& path, bool srgb = false); + static Ref Create(const std::string& path, bool srgb = false, bool isLUT = false); virtual TextureFormat GetFormat() const = 0;