From 7e1ac5e167cea42b0a77cfc220845ae90a7263b3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 2 Oct 2025 18:48:14 +0200 Subject: [PATCH] Fix sky rendering in ortho and oblique projection #3448 --- Content/Shaders/Sky.flax | 4 +- Source/Engine/Level/Actors/Sky.cpp | 74 +++----------------------- Source/Engine/Level/Actors/Sky.h | 4 +- Source/Engine/Renderer/GBufferPass.cpp | 14 ++++- Source/Shaders/Sky.shader | 57 ++++---------------- 5 files changed, 34 insertions(+), 119 deletions(-) diff --git a/Content/Shaders/Sky.flax b/Content/Shaders/Sky.flax index 87a5b6b3a..a568db451 100644 --- a/Content/Shaders/Sky.flax +++ b/Content/Shaders/Sky.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28d44ef295d989d49ad4d59d6581eee921bc5fa5237e046d271a433454496388 -size 3463 +oid sha256:8541d1f0590167498f44da231f6de4f2938e15b26a5eb58e27b5067e1c882be8 +size 2252 diff --git a/Source/Engine/Level/Actors/Sky.cpp b/Source/Engine/Level/Actors/Sky.cpp index 4e635489f..6d7d5efe2 100644 --- a/Source/Engine/Level/Actors/Sky.cpp +++ b/Source/Engine/Level/Actors/Sky.cpp @@ -21,7 +21,8 @@ #endif GPU_CB_STRUCT(Data { - Matrix WVP; + Matrix WorldViewProjection; + Matrix InvViewProjection; Float3 ViewOffset; float Padding; ShaderGBufferData GBuffer; @@ -30,9 +31,6 @@ GPU_CB_STRUCT(Data { Sky::Sky(const SpawnParams& params) : Actor(params) - , _shader(nullptr) - , _psSky(nullptr) - , _psFog(nullptr) { _drawNoCulling = 1; _drawCategory = SceneRendering::PreRender; @@ -52,7 +50,6 @@ Sky::Sky(const SpawnParams& params) Sky::~Sky() { SAFE_DELETE_GPU_RESOURCE(_psSky); - SAFE_DELETE_GPU_RESOURCE(_psFog); } void Sky::InitConfig(ShaderAtmosphericFogData& config) const @@ -91,7 +88,7 @@ void Sky::Draw(RenderContext& renderContext) if (HasContentLoaded() && EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::Sky)) { // Ensure to have pipeline state cache created - if (_psSky == nullptr || _psFog == nullptr) + if (_psSky == nullptr) { const auto shader = _shader->GetShader(); @@ -113,21 +110,6 @@ void Sky::Draw(RenderContext& renderContext) LOG(Warning, "Cannot create graphics pipeline state object for '{0}'.", ToString()); } } - if (_psFog == nullptr) - { - _psFog = GPUDevice::Instance->CreatePipelineState(); - - GPUPipelineState::Description psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle; - psDesc.PS = shader->GetPS("PS_Fog"); - psDesc.DepthWriteEnable = false; - psDesc.DepthClipEnable = false; - psDesc.BlendMode = BlendingMode::Additive; - - if (_psFog->Init(psDesc)) - { - LOG(Warning, "Cannot create graphics pipeline state object for '{0}'.", ToString()); - } - } } // Register for the sky and fog pass @@ -139,7 +121,6 @@ void Sky::Draw(RenderContext& renderContext) void Sky::Serialize(SerializeStream& stream, const void* otherObj) { - // Base Actor::Serialize(stream, otherObj); SERIALIZE_GET_OTHER_OBJ(Sky); @@ -152,7 +133,6 @@ void Sky::Serialize(SerializeStream& stream, const void* otherObj) void Sky::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) { - // Base Actor::Deserialize(stream, modifier); DESERIALIZE_MEMBER(Sun, SunLight); @@ -173,39 +153,7 @@ bool Sky::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal) void Sky::DrawFog(GPUContext* context, RenderContext& renderContext, GPUTextureView* output) { - // Get precomputed cache and bind it to the pipeline - AtmosphereCache cache; - if (!AtmospherePreCompute::GetCache(&cache)) - return; - context->BindSR(4, cache.Transmittance); - context->BindSR(5, cache.Irradiance); - context->BindSR(6, cache.Inscatter->ViewVolume()); - - // Bind GBuffer inputs - context->BindSR(0, renderContext.Buffers->GBuffer0); - context->BindSR(1, renderContext.Buffers->GBuffer1); - context->BindSR(2, renderContext.Buffers->GBuffer2); - context->BindSR(3, renderContext.Buffers->DepthBuffer); - - // Setup constants data - Data data; - GBufferPass::SetInputs(renderContext.View, data.GBuffer); - data.ViewOffset = renderContext.View.Origin + GetPosition(); - InitConfig(data.Fog); - data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f; - bool useSpecularLight = EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::SpecularLight); - if (!useSpecularLight) - { - data.Fog.AtmosphericFogSunDiscScale = 0; - } - - // Bind pipeline - auto cb = _shader->GetShader()->GetCB(0); - context->UpdateCB(cb, &data); - context->BindCB(0, cb); - context->SetState(_psFog); - context->SetRenderTarget(output); - context->DrawFullscreenTriangle(); + MISSING_CODE("sky fog"); } bool Sky::IsDynamicSky() const @@ -231,14 +179,14 @@ void Sky::ApplySky(GPUContext* context, RenderContext& renderContext, const Matr // Setup constants data Matrix m; Data data; - Matrix::Multiply(world, renderContext.View.Frustum.GetMatrix(), m); - Matrix::Transpose(m, data.WVP); + Matrix::Multiply(world, renderContext.View.ViewProjection(), m); + Matrix::Transpose(m, data.WorldViewProjection); + Matrix::Transpose(renderContext.View.IVP, data.InvViewProjection); GBufferPass::SetInputs(renderContext.View, data.GBuffer); data.ViewOffset = renderContext.View.Origin + GetPosition(); InitConfig(data.Fog); //data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f; - bool useSpecularLight = EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::SpecularLight); - if (!useSpecularLight) + if (EnumHasNoneFlags(renderContext.View.Flags, ViewFlags::SpecularLight)) { // Hide sun disc if specular light is disabled data.Fog.AtmosphericFogSunDiscScale = 0; @@ -253,11 +201,8 @@ void Sky::ApplySky(GPUContext* context, RenderContext& renderContext, const Matr void Sky::EndPlay() { - // Cleanup SAFE_DELETE_GPU_RESOURCE(_psSky); - SAFE_DELETE_GPU_RESOURCE(_psFog); - // Base Actor::EndPlay(); } @@ -268,7 +213,6 @@ void Sky::OnEnable() GetSceneRendering()->AddViewportIcon(this); #endif - // Base Actor::OnEnable(); } @@ -279,13 +223,11 @@ void Sky::OnDisable() #endif GetSceneRendering()->RemoveActor(this, _sceneRenderingKey); - // Base Actor::OnDisable(); } void Sky::OnTransformChanged() { - // Base Actor::OnTransformChanged(); _box = BoundingBox(_transform.Translation); diff --git a/Source/Engine/Level/Actors/Sky.h b/Source/Engine/Level/Actors/Sky.h index 65bcc631a..61bb048ef 100644 --- a/Source/Engine/Level/Actors/Sky.h +++ b/Source/Engine/Level/Actors/Sky.h @@ -20,8 +20,7 @@ class FLAXENGINE_API Sky : public Actor, public IAtmosphericFogRenderer, public DECLARE_SCENE_OBJECT(Sky); private: AssetReference _shader; - GPUPipelineState* _psSky; - GPUPipelineState* _psFog; + GPUPipelineState* _psSky = nullptr; int32 _sceneRenderingKey = -1; public: @@ -57,7 +56,6 @@ private: void OnShaderReloading(Asset* obj) { _psSky = nullptr; - _psFog = nullptr; } #endif void InitConfig(ShaderAtmosphericFogData& config) const; diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index 9d3684010..7c9abb413 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -19,6 +19,7 @@ #include "Engine/Content/Content.h" #include "Engine/Content/Assets/Model.h" #include "Engine/Level/Actors/Decal.h" +#include "Engine/Level/Actors/Sky.h" #include "Engine/Engine/Engine.h" GPU_CB_STRUCT(GBufferPassData { @@ -416,8 +417,17 @@ void GBufferPass::DrawSky(RenderContext& renderContext, GPUContext* context) // Calculate sphere model transform to cover far plane Matrix m1, m2; - Matrix::Scaling(renderContext.View.Far / ((float)box.GetSize().Y * 0.5f) * 0.95f, m1); // Scale to fit whole view frustum - Matrix::CreateWorld(renderContext.View.Position, Float3::Up, Float3::Backward, m2); // Rotate sphere model + float size = renderContext.View.Far; + Float3 origin = renderContext.View.Position; + if (dynamic_cast(renderContext.List->Sky)) // TODO: refactor sky rendering (eg. let sky draw with custom projection) + { + BoundingSphere frustumBounds; + renderContext.View.CullingFrustum.GetSphere(frustumBounds); + origin = frustumBounds.Center; + size = frustumBounds.Radius; + } + Matrix::Scaling(size / ((float)box.GetSize().Y * 0.5f) * 0.95f, m1); // Scale to fit whole view frustum + Matrix::CreateWorld(origin, Float3::Up, Float3::Backward, m2); // Rotate sphere model m1 *= m2; // Draw sky diff --git a/Source/Shaders/Sky.shader b/Source/Shaders/Sky.shader index af5d0053c..de29e5d3f 100644 --- a/Source/Shaders/Sky.shader +++ b/Source/Shaders/Sky.shader @@ -7,7 +7,8 @@ #include "./Flax/AtmosphereFog.hlsl" META_CB_BEGIN(0, Data) -float4x4 WVP; +float4x4 WorldViewProjection; +float4x4 InvViewProjection; float3 ViewOffset; float Padding; GBufferData GBuffer; @@ -18,7 +19,7 @@ DECLARE_GBUFFERDATA_ACCESS(GBuffer) struct MaterialInput { - float4 Position : SV_Position; + float4 Position : SV_Position; float4 ScreenPos : TEXCOORD0; }; @@ -30,12 +31,9 @@ MaterialInput VS(ModelInput_PosOnly input) MaterialInput output; // Compute vertex position - output.Position = mul(float4(input.Position.xyz, 1), WVP); + output.Position = mul(float4(input.Position.xyz, 1), WorldViewProjection); output.ScreenPos = output.Position; - // Place pixels on the far plane - output.Position = output.Position.xyzz; - return output; } @@ -45,15 +43,15 @@ GBufferOutput PS_Sky(MaterialInput input) { GBufferOutput output; - // Obtain UVs corresponding to the current pixel - float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5); + // Calculate view vector (unproject at the far plane) + GBufferData gBufferData = GetGBufferData(); + float4 clipPos = float4(input.ScreenPos.xy / input.ScreenPos.w, 1.0, 1.0); + clipPos = mul(clipPos, InvViewProjection); + float3 worldPos = clipPos.xyz / clipPos.w; + float3 viewVector = normalize(worldPos - gBufferData.ViewPos); // Sample atmosphere color - GBufferData gBufferData = GetGBufferData(); - float3 vsPos = GetViewPos(gBufferData, uv, LinearZ2DeviceDepth(gBufferData, 1)); - float3 wsPos = mul(float4(vsPos, 1), gBufferData.InvViewMatrix).xyz; - float3 viewVector = wsPos - gBufferData.ViewPos; - float4 color = GetAtmosphericFog(AtmosphericFog, gBufferData.ViewFar, wsPos + ViewOffset, gBufferData.ViewPos + ViewOffset); + float4 color = GetAtmosphericFog(AtmosphericFog, gBufferData.ViewFar, gBufferData.ViewPos + ViewOffset, viewVector, gBufferData.ViewFar, float3(0, 0, 0)); // Pack GBuffer output.Light = color; @@ -64,36 +62,3 @@ GBufferOutput PS_Sky(MaterialInput input) return output; } - -META_PS(true, FEATURE_LEVEL_ES2) -float4 PS_Fog(Quad_VS2PS input) : SV_Target0 -{ - float4 result; - /* - // Sample GBuffer - GBufferSample gBuffer = SampleGBuffer(GBuffer, input.TexCoord); - - // TODO: set valid scene color for better inscatter reflectance - //float3 sceneColor = gBuffer.Color * AtmosphericFogDensityOffset; - float3 sceneColor = float3(0, 0, 0); - - // Sample atmosphere color - float3 viewVector = gBuffer.WorldPos - GBuffer.ViewPos; - float SceneDepth = length(ViewVector); - result = GetAtmosphericFog(AtmosphericFog, GBuffer.ViewFar, GBuffer.ViewPos, viewVector, SceneDepth, sceneColor); - - //result.rgb = normalize(ViewVector); - //result.rgb = ViewVector; - //result.rgb = SceneDepth.xxx / GBuffer.ViewFar * 0.5f; - - //result = float4(input.TexCoord, 0, 1); - //result = AtmosphereTransmittanceTexture.Sample(SamplerLinearClamp, input.TexCoord); - //result = float4(AtmosphereIrradianceTexture.Sample(SamplerLinearClamp, input.TexCoord).rgb*5.0, 1.0); - //result = AtmosphereInscatterTexture.Sample(SamplerLinearClamp, float3(input.TexCoord.xy, (AtmosphericFogSunDirection.x+1.0)/2.0)); - */ - - // TODO: finish fog - result = float4(1, 0, 0, 1); - - return result; -}