add simple fog

This commit is contained in:
2026-04-06 19:06:04 +08:00
parent 1f4d7eff71
commit 3c64abd77e
16 changed files with 171 additions and 18 deletions

View File

@ -664,7 +664,7 @@ namespace Prism
{ {
SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y); SceneRenderer::SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_EditorScene->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, 10000.0f)); 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); m_EditorCamera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 }); ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });

View File

@ -75,6 +75,9 @@ const float Epsilon = 0.00001;
const int LightCount = 1; const int LightCount = 1;
const vec3 Fdielectric = vec3(0.04); const vec3 Fdielectric = vec3(0.04);
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 o_BloomColor;
struct DirectionalLight { struct DirectionalLight {
vec3 Direction; vec3 Direction;
vec3 Radiance; vec3 Radiance;
@ -113,8 +116,6 @@ in VertexOutput
vec4 FragPosLightSpace; vec4 FragPosLightSpace;
} vs_Input; } vs_Input;
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 o_BloomColor;
uniform DirectionalLight u_DirectionalLights; uniform DirectionalLight u_DirectionalLights;
uniform vec3 u_CameraPosition; uniform vec3 u_CameraPosition;

View File

@ -61,6 +61,9 @@ const float Epsilon = 0.00001;
const int LightCount = 1; const int LightCount = 1;
const vec3 Fdielectric = vec3(0.04); const vec3 Fdielectric = vec3(0.04);
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 o_BloomColor;
struct DirectionalLight { struct DirectionalLight {
vec3 Direction; vec3 Direction;
vec3 Radiance; vec3 Radiance;
@ -100,9 +103,6 @@ in VertexOutput
vec4 FragPosLightSpace; vec4 FragPosLightSpace;
} vs_Input; } vs_Input;
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 o_BloomColor;
uniform DirectionalLight u_DirectionalLights; uniform DirectionalLight u_DirectionalLights;
uniform int u_PointLightCount; uniform int u_PointLightCount;

View File

@ -22,8 +22,20 @@ layout(location = 1) out vec4 o_BloomTexture;
in vec2 v_TexCoord; in vec2 v_TexCoord;
uniform sampler2DMS u_Texture; uniform sampler2DMS u_Texture;
uniform sampler2DMS u_DepthTexture;
uniform sampler2D u_BloomTexture; uniform sampler2D u_BloomTexture;
uniform mat4 u_InvProjection;
uniform mat4 u_InvView;
// Fog
uniform float u_FogEnabled;
uniform vec3 u_FogColor;
uniform float u_FogDensity; // 雾密度,典型值 0.01~0.05
uniform float u_FogHeight; // 雾的起始高度(世界 Y 坐标),低于此高度雾最浓
uniform float u_FogHeightFalloff; // 高度衰减系数,值越大高度影响越剧烈(典型 0.5~2.0
uniform bool u_EnableAutoExposure; uniform bool u_EnableAutoExposure;
uniform float u_ManualExposure; uniform float u_ManualExposure;
@ -62,7 +74,7 @@ float MultiSampleDepth(sampler2DMS tex, vec2 tc)
ivec2 texCoord = ivec2(tc * texSize); ivec2 texCoord = ivec2(tc * texSize);
float result = 0.0; float result = 0.0;
for (int i = 0; i < u_TextureSamples; i++) for (int i = 0; i < u_TextureSamples; i++)
result += texelFetch(tex, texCoord, i).r; result += texelFetch(tex, texCoord, i).r;
result /= float(u_TextureSamples); result /= float(u_TextureSamples);
return result; return result;
} }
@ -82,10 +94,14 @@ void main()
color += bloomColor; color += bloomColor;
} }
float exposure = 1.0f;
if(u_EnableAutoExposure) if(u_EnableAutoExposure)
color *= u_Exposure; exposure = u_Exposure;
else else
color *= u_ManualExposure; exposure = u_ManualExposure;
color *= exposure;
// Reinhard tonemapping operator. // Reinhard tonemapping operator.
// see: "Photographic Tone Reproduction for Digital Images", eq. 4 // see: "Photographic Tone Reproduction for Digital Images", eq. 4
@ -95,6 +111,49 @@ void main()
// Scale color by ratio of average luminances. // Scale color by ratio of average luminances.
vec3 mappedColor = (mappedLuminance / luminance) * color; vec3 mappedColor = (mappedLuminance / luminance) * color;
if (u_FogEnabled > 0.5)
{
// 1. 获取深度并重建视空间坐标
float depth = MultiSampleDepth(u_DepthTexture, v_TexCoord);
vec4 clipPos = vec4(v_TexCoord * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
vec4 viewPos4 = u_InvProjection * clipPos;
viewPos4 /= viewPos4.w;
vec3 viewPos = viewPos4.xyz; // 视空间坐标相机为原点Z 轴向内)
// 2. 距离雾因子(指数雾)
float distance = length(viewPos);
float distanceFactor = 1.0 - exp(-distance * u_FogDensity);
// 可选:指数平方雾(更平滑)
// float distanceFactor = 1.0 - exp(-pow(distance * u_FogDensity, 2.0));
// 3. 高度雾因子(基于世界 Y
// 将视空间坐标转换到世界空间
vec4 worldPos4 = u_InvView* vec4(viewPos, 1.0);
vec3 worldPos = worldPos4.xyz / worldPos4.w;
float worldY = worldPos.y;
float heightFactor = 0.0;
if (worldY < u_FogHeight)
{
// 低于起始高度:雾最浓,因子为 1
heightFactor = 1.0;
}
else
{
// 高于起始高度:指数衰减,高度越高雾越淡
float deltaY = worldY - u_FogHeight;
heightFactor = exp(-deltaY * u_FogHeightFalloff);
}
// 可选:使用 clamp 限制范围
heightFactor = clamp(heightFactor, 0.0, 1.0);
// 4. 综合雾因子(可相乘,也可取最大值,通常相乘)
float fogFactor = distanceFactor * heightFactor;
// 5. 混合雾颜色(雾颜色直接使用 u_FogColor已在 LDR 空间)
mappedColor = mix(mappedColor, u_FogColor, fogFactor);
}
// Gamma correction. // Gamma correction.
o_Color = vec4(pow(mappedColor, vec3(1.0 / gamma)), 1.0); o_Color = vec4(pow(mappedColor, vec3(1.0 / gamma)), 1.0);

View File

@ -5,6 +5,7 @@
#include "DefaultAssetEditors.h" #include "DefaultAssetEditors.h"
#include "Prism/Asset/AssetSerializer.h" #include "Prism/Asset/AssetSerializer.h"
#include "Prism/Core/Log.h"
namespace Prism namespace Prism
{ {

View File

@ -10,6 +10,8 @@
namespace Prism namespace Prism
{ {
class RenderPass;
class PhysicsMaterialEditor : public AssetEditor class PhysicsMaterialEditor : public AssetEditor
{ {
public: public:

View File

@ -148,6 +148,17 @@ namespace Prism
}); });
} }
void OpenGLShader::SetFloatArray(const std::string& name, float* arr, int count)
{
Renderer::Submit([=]()
{
for (int i = 0; i < count; i++)
{
UploadUniformFloat(name, arr[i]);
}
});
}
void OpenGLShader::SetInt(const std::string& name, int value) void OpenGLShader::SetInt(const std::string& name, int value)
{ {
Renderer::Submit([=]() { Renderer::Submit([=]() {

View File

@ -31,6 +31,7 @@ namespace Prism
virtual void SetFloat(const std::string& name, float value) override; virtual void SetFloat(const std::string& name, float value) override;
virtual void SetFloat2(const std::string& name, const glm::vec2& value) override; virtual void SetFloat2(const std::string& name, const glm::vec2& value) override;
virtual void SetFloat3(const std::string& name, const glm::vec3& value) override; virtual void SetFloat3(const std::string& name, const glm::vec3& value) override;
virtual void SetFloatArray(const std::string& name, float* arr, int count) override;
virtual void SetInt(const std::string& name, int value) override; virtual void SetInt(const std::string& name, int value) override;
virtual void SetUInt(const std::string& name, unsigned int value) override; virtual void SetUInt(const std::string& name, unsigned int value) override;
virtual void SetMat4(const std::string& name, const glm::mat4& value) override; virtual void SetMat4(const std::string& name, const glm::mat4& value) override;

View File

@ -13,4 +13,20 @@ namespace Prism
{ {
} }
float Camera::GetNear() const
{
if (m_ProjectionMatrix[3][3] == 1.0f) // 正交投影
return (m_ProjectionMatrix[3][2] - 1.0f) / m_ProjectionMatrix[2][2];
else // 透视投影
return m_ProjectionMatrix[3][2] / (m_ProjectionMatrix[2][2] - 1.0f);
}
float Camera::GetFar() const
{
if (m_ProjectionMatrix[3][3] == 1.0f) // 正交
return (m_ProjectionMatrix[3][2] + 1.0f) / m_ProjectionMatrix[2][2];
else // 透视
return m_ProjectionMatrix[3][2] / (m_ProjectionMatrix[2][2] + 1.0f);
}
} }

View File

@ -24,6 +24,9 @@ namespace Prism
const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; } const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; }
float GetNear() const;
float GetFar() const;
void SetProjectionMatrix(const glm::mat4& projectionMatrix) { m_ProjectionMatrix = projectionMatrix; } void SetProjectionMatrix(const glm::mat4& projectionMatrix) { m_ProjectionMatrix = projectionMatrix; }
float GetExposure() const { return m_Exposure; } float GetExposure() const { return m_Exposure; }

View File

@ -201,6 +201,16 @@ namespace Prism
DrawIndexed(6, PrimitiveType::Triangles, depthTest, cullFace); DrawIndexed(6, PrimitiveType::Triangles, depthTest, cullFace);
} }
void Renderer::SubmitFullscreenQuad(const bool depthTest, const bool cullFace)
{
s_Data.m_FullscreenQuadVertexBuffer->Bind();
s_Data.m_FullscreenQuadPipeline->Bind();
s_Data.m_FullscreenQuadIndexBuffer->Bind();
DrawIndexed(6, PrimitiveType::Triangles, depthTest, cullFace);
}
void Renderer::SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials) void Renderer::SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials)
{ {
// auto material = overrideMaterial ? overrideMaterial : mesh->GetMaterialInstance(); // auto material = overrideMaterial ? overrideMaterial : mesh->GetMaterialInstance();

View File

@ -61,6 +61,7 @@ namespace Prism
static void SubmitQuad(Ref<MaterialInstance>& material, const glm::mat4& transform = glm::mat4(1.0f)); static void SubmitQuad(Ref<MaterialInstance>& material, const glm::mat4& transform = glm::mat4(1.0f));
static void SubmitFullscreenQuad(Ref<MaterialInstance> material); static void SubmitFullscreenQuad(Ref<MaterialInstance> material);
static void SubmitFullscreenQuad(bool depthTest = true, bool cullFace = true);
static void SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials = {}); static void SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const std::vector<Ref<MaterialInstance>>& overrideMaterials = {});
static void SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial = nullptr); static void SubmitMesh(Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial = nullptr);
static void SubmitMeshWithShader(Ref<Mesh> mesh, const glm::mat4& transform, Ref<Shader> shader); static void SubmitMeshWithShader(Ref<Mesh> mesh, const glm::mat4& transform, Ref<Shader> shader);

View File

@ -11,7 +11,6 @@
#include "Renderer2D.h" #include "Renderer2D.h"
#include "SceneRenderer.h" #include "SceneRenderer.h"
#include "StorageBuffer.h" #include "StorageBuffer.h"
#include "glad/glad.h"
#include "Prism/Scene/Components.h" #include "Prism/Scene/Components.h"
#include "RHI/RHICommandBuffer.h" #include "RHI/RHICommandBuffer.h"
#include "RHI/RHIDevice.h" #include "RHI/RHIDevice.h"
@ -31,6 +30,15 @@ namespace Prism
Ref<Environment> SceneEnvironment; Ref<Environment> SceneEnvironment;
} SceneData; } SceneData;
struct FogData
{
bool FogEnabled = false;
glm::vec3 FogColor{1.0f};
float FogDensity = 0.01f;
float FogHeight = 0.0f;
float FogHeightFalloff = 0.01f;
}FogData;
Ref<Texture2D> BRDFLUT; Ref<Texture2D> BRDFLUT;
Ref<Shader> CompositeShader; Ref<Shader> CompositeShader;
Ref<Shader> BloomBlurShader; Ref<Shader> BloomBlurShader;
@ -815,10 +823,10 @@ namespace Prism
auto reg = rd->GetRegister(); auto reg = rd->GetRegister();
auto tex = s_Data.ShadowMapRenderPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID(); auto tex = s_Data.ShadowMapRenderPass->GetSpecification().TargetFramebuffer->GetDepthAttachmentRendererID();
Renderer::Submit([reg, tex]() mutable Renderer::Submit([reg, tex, cmd]() mutable
{ {
glBindTextureUnit(reg, tex); cmd->BindTextureUnit(reg, tex);
glBindSampler(reg, s_Data.ShadowMapSampler); cmd->BindSampler(reg, s_Data.ShadowMapSampler);
}); });
} }
@ -1039,17 +1047,39 @@ namespace Prism
s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples); s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples);
s_Data.CompositeShader->SetBool("u_EnableBloom", s_Data.EnableBloom); s_Data.CompositeShader->SetBool("u_EnableBloom", s_Data.EnableBloom);
// 绑定几何阶段颜色纹理(多重采样)
// Fog
s_Data.CompositeShader->SetFloat("u_FogEnabled", s_Data.FogData.FogEnabled ? 1.0f : 0.0f);
if (s_Data.FogData.FogEnabled)
{
s_Data.CompositeShader->SetMat4("u_InvProjection", glm::inverse(s_Data.SceneData.SceneCamera.Camera.GetProjectionMatrix()));
s_Data.CompositeShader->SetMat4("u_InvView", glm::inverse(s_Data.SceneData.SceneCamera.ViewMatrix));
s_Data.CompositeShader->SetFloat3("u_FogColor", s_Data.FogData.FogColor);
s_Data.CompositeShader->SetFloat("u_FogDensity", s_Data.FogData.FogDensity);
s_Data.CompositeShader->SetFloat("u_FogHeight", s_Data.FogData.FogHeight);
s_Data.CompositeShader->SetFloat("u_FogHeightFalloff", s_Data.FogData.FogHeightFalloff);
}
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture(); s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture();
s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindDepthTexture(1); s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindDepthTexture(1);
if (s_Data.EnableBloom) if (s_Data.EnableBloom)
{ {
s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->BindTexture(0, 2); s_Data.BloomBlendPass->GetSpecification().TargetFramebuffer->BindTexture(0, 2);
s_Data.CompositeShader->SetInt("u_BloomTexture", 2); // 告诉着色器使用单元2 s_Data.CompositeShader->SetInt("u_BloomTexture", 2);
} }
Renderer::SubmitFullscreenQuad(nullptr); Renderer::SubmitFullscreenQuad(false);
auto depthFB = s_Data.GeoPass->GetSpecification().TargetFramebuffer;
auto outFB = outRenderPass->GetSpecification().TargetFramebuffer;
Renderer::Submit([cmd, depthFB, outFB]()
{
cmd->BindFramebuffer(FramebufferTarget::Read, depthFB->GetDepthAttachmentRendererID());
cmd->BindFramebuffer(FramebufferTarget::Draw, outFB->GetDepthAttachmentRendererID());
cmd->BlitFramebuffer(0, 0, depthFB->GetWidth(), depthFB->GetHeight(),
0, 0, outFB->GetWidth(), outFB->GetHeight(), BlitMask::Depth, BlitFilter::Nearest);
});
Renderer::EndRenderPass(); Renderer::EndRenderPass();
} }
@ -1110,6 +1140,22 @@ namespace Prism
UI::Property("Shadow Pass time", s_Stats.ShadowPass); UI::Property("Shadow Pass time", s_Stats.ShadowPass);
UI::Property("AutoExposure Pass time", s_Stats.AutoExposurePass); UI::Property("AutoExposure Pass time", s_Stats.AutoExposurePass);
if (UI::BeginTreeNode("FogConfig", false))
{
UI::BeginPropertyGrid();
UI::Property("Enabled", s_Data.FogData.FogEnabled);
if (s_Data.FogData.FogEnabled)
{
UI::PropertyColor("Fog Color", s_Data.FogData.FogColor);
UI::Property("Fog Density", s_Data.FogData.FogDensity, 0.001f, 0.001f, 0.1f);
UI::Property("Fog Height", s_Data.FogData.FogHeight, 0.001f, -10.0f, 10.0f);
UI::Property("Fog HeightFalloff", s_Data.FogData.FogHeightFalloff, 0.001f, 0.001f, 0.5f);
}
UI::EndPropertyGrid();
UI::EndTreeNode();
}
if (UI::BeginTreeNode("Grid Config", false)) if (UI::BeginTreeNode("Grid Config", false))
{ {
// Grid plane: 0 = XZ (Y up), 1 = XY (Z forward), 2 = YZ (X right) // Grid plane: 0 = XZ (Y up), 1 = XY (Z forward), 2 = YZ (X right)

View File

@ -215,8 +215,6 @@ namespace Prism
const auto fbWidth = fb->GetWidth(); const auto fbWidth = fb->GetWidth();
const auto fbHeight = fb->GetHeight(); const auto fbHeight = fb->GetHeight();
Renderer::Submit([fb, fbWidth, fbHeight]() Renderer::Submit([fb, fbWidth, fbHeight]()
{ {
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb->GetColorAttachmentRendererID()); glBindFramebuffer(GL_READ_FRAMEBUFFER, fb->GetColorAttachmentRendererID());

View File

@ -116,6 +116,7 @@ namespace Prism
virtual void SetFloat(const std::string& name, float value) = 0; virtual void SetFloat(const std::string& name, float value) = 0;
virtual void SetFloat2(const std::string& name, const glm::vec2& value) = 0; virtual void SetFloat2(const std::string& name, const glm::vec2& value) = 0;
virtual void SetFloat3(const std::string& name, const glm::vec3& value) = 0; virtual void SetFloat3(const std::string& name, const glm::vec3& value) = 0;
virtual void SetFloatArray(const std::string& name, float* arr, int count) = 0;
virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0; virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0;
virtual void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value, bool bind = true) = 0; virtual void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value, bool bind = true) = 0;

View File

@ -239,7 +239,10 @@ namespace Prism
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
} }
#ifdef PRISM_RUNTIME
SceneRenderer::FlushToScreen(); SceneRenderer::FlushToScreen();
#endif
SceneRenderer::EndScene(); SceneRenderer::EndScene();
} }