Add GlobalSurfaceAtlas pass to Renderer (wip)
This commit is contained in:
BIN
Content/Shaders/GlobalSurfaceAtlas.flax
(Stored with Git LFS)
Normal file
BIN
Content/Shaders/GlobalSurfaceAtlas.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -69,6 +69,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
data.AddRootEngineAsset(TEXT("Shaders/BitonicSort"));
|
data.AddRootEngineAsset(TEXT("Shaders/BitonicSort"));
|
||||||
data.AddRootEngineAsset(TEXT("Shaders/GPUParticlesSorting"));
|
data.AddRootEngineAsset(TEXT("Shaders/GPUParticlesSorting"));
|
||||||
data.AddRootEngineAsset(TEXT("Shaders/GlobalSignDistanceField"));
|
data.AddRootEngineAsset(TEXT("Shaders/GlobalSignDistanceField"));
|
||||||
|
data.AddRootEngineAsset(TEXT("Shaders/GlobalSurfaceAtlas"));
|
||||||
data.AddRootEngineAsset(TEXT("Shaders/Quad"));
|
data.AddRootEngineAsset(TEXT("Shaders/Quad"));
|
||||||
data.AddRootEngineAsset(TEXT("Shaders/Reflections"));
|
data.AddRootEngineAsset(TEXT("Shaders/Reflections"));
|
||||||
data.AddRootEngineAsset(TEXT("Shaders/Shadows"));
|
data.AddRootEngineAsset(TEXT("Shaders/Shadows"));
|
||||||
|
|||||||
@@ -1408,6 +1408,7 @@ namespace FlaxEditor.Viewport
|
|||||||
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"),
|
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"),
|
||||||
new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw"),
|
new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw"),
|
||||||
new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF"),
|
new ViewModeOptions(ViewMode.GlobalSDF, "Global SDF"),
|
||||||
|
new ViewModeOptions(ViewMode.GlobalSurfaceAtlas, "Global Surface Atlas"),
|
||||||
};
|
};
|
||||||
|
|
||||||
private void WidgetCamSpeedShowHide(Control cm)
|
private void WidgetCamSpeedShowHide(Control cm)
|
||||||
|
|||||||
@@ -854,9 +854,14 @@ API_ENUM() enum class ViewMode
|
|||||||
QuadOverdraw = 23,
|
QuadOverdraw = 23,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draw global Sign Distant Field (SDF) preview.
|
/// Draw Global Sign Distant Field (SDF) preview.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
GlobalSDF = 24,
|
GlobalSDF = 24,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draw Global Surface Atlas preview.
|
||||||
|
/// </summary>
|
||||||
|
GlobalSurfaceAtlas = 25,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
170
Source/Engine/Renderer/GlobalSurfaceAtlasPass.cpp
Normal file
170
Source/Engine/Renderer/GlobalSurfaceAtlasPass.cpp
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#include "GlobalSurfaceAtlasPass.h"
|
||||||
|
#include "GlobalSignDistanceFieldPass.h"
|
||||||
|
#include "RenderList.h"
|
||||||
|
#include "Engine/Engine/Engine.h"
|
||||||
|
#include "Engine/Content/Content.h"
|
||||||
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
|
#include "Engine/Graphics/RenderTask.h"
|
||||||
|
#include "Engine/Graphics/RenderBuffers.h"
|
||||||
|
#include "Engine/Graphics/RenderTargetPool.h"
|
||||||
|
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||||
|
|
||||||
|
PACK_STRUCT(struct Data0
|
||||||
|
{
|
||||||
|
Vector3 ViewWorldPos;
|
||||||
|
float ViewNearPlane;
|
||||||
|
Vector3 Padding00;
|
||||||
|
float ViewFarPlane;
|
||||||
|
Vector4 ViewFrustumWorldRays[4];
|
||||||
|
GlobalSignDistanceFieldPass::GlobalSDFData GlobalSDF;
|
||||||
|
});
|
||||||
|
|
||||||
|
class GlobalSurfaceAtlasCustomBuffer : public RenderBuffers::CustomBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GPUTexture* Dummy = nullptr; // TODO use some actual atlas textures
|
||||||
|
GlobalSurfaceAtlasPass::BindingData Result;
|
||||||
|
|
||||||
|
~GlobalSurfaceAtlasCustomBuffer()
|
||||||
|
{
|
||||||
|
RenderTargetPool::Release(Dummy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
String GlobalSurfaceAtlasPass::ToString() const
|
||||||
|
{
|
||||||
|
return TEXT("GlobalSurfaceAtlasPass");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalSurfaceAtlasPass::Init()
|
||||||
|
{
|
||||||
|
// Check platform support
|
||||||
|
const auto device = GPUDevice::Instance;
|
||||||
|
_supported = device->GetFeatureLevel() >= FeatureLevel::SM5 && device->Limits.HasCompute && device->Limits.HasTypedUAVLoad;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalSurfaceAtlasPass::setupResources()
|
||||||
|
{
|
||||||
|
// Load shader
|
||||||
|
if (!_shader)
|
||||||
|
{
|
||||||
|
_shader = Content::LoadAsyncInternal<Shader>(TEXT("Shaders/GlobalSurfaceAtlas"));
|
||||||
|
if (_shader == nullptr)
|
||||||
|
return true;
|
||||||
|
#if COMPILE_WITH_DEV_ENV
|
||||||
|
_shader.Get()->OnReloading.Bind<GlobalSurfaceAtlasPass, &GlobalSurfaceAtlasPass::OnShaderReloading>(this);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (!_shader->IsLoaded())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const auto device = GPUDevice::Instance;
|
||||||
|
const auto shader = _shader->GetShader();
|
||||||
|
_cb0 = shader->GetCB(0);
|
||||||
|
|
||||||
|
// Create pipeline state
|
||||||
|
GPUPipelineState::Description psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
|
||||||
|
if (!_psDebug)
|
||||||
|
{
|
||||||
|
_psDebug = device->CreatePipelineState();
|
||||||
|
psDesc.PS = shader->GetPS("PS_Debug");
|
||||||
|
if (_psDebug->Init(psDesc))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if COMPILE_WITH_DEV_ENV
|
||||||
|
|
||||||
|
void GlobalSurfaceAtlasPass::OnShaderReloading(Asset* obj)
|
||||||
|
{
|
||||||
|
SAFE_DELETE_GPU_RESOURCE(_psDebug);
|
||||||
|
invalidateResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void GlobalSurfaceAtlasPass::Dispose()
|
||||||
|
{
|
||||||
|
RendererPass::Dispose();
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
SAFE_DELETE_GPU_RESOURCE(_psDebug);
|
||||||
|
_cb0 = nullptr;
|
||||||
|
_shader = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* context, BindingData& result)
|
||||||
|
{
|
||||||
|
// Skip if not supported
|
||||||
|
if (setupResources())
|
||||||
|
return true;
|
||||||
|
if (renderContext.List->Scenes.Count() == 0)
|
||||||
|
return true;
|
||||||
|
auto& surfaceAtlasData = *renderContext.Buffers->GetCustomBuffer<GlobalSurfaceAtlasCustomBuffer>(TEXT("GlobalSurfaceAtlas"));
|
||||||
|
|
||||||
|
// Skip if already done in the current frame
|
||||||
|
const auto currentFrame = Engine::FrameCount;
|
||||||
|
if (surfaceAtlasData.LastFrameUsed == currentFrame)
|
||||||
|
{
|
||||||
|
result = surfaceAtlasData.Result;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROFILE_GPU_CPU("Global Surface Atlas");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
// TODO: configurable via graphics settings
|
||||||
|
const int32 resolution = 4096;
|
||||||
|
// TODO: configurable via postFx settings (maybe use Global SDF distance?)
|
||||||
|
const float distance = 20000;
|
||||||
|
|
||||||
|
// TODO: Initialize buffers
|
||||||
|
surfaceAtlasData.LastFrameUsed = currentFrame;
|
||||||
|
|
||||||
|
// TODO: Rasterize world geometry into Global Surface Atlas
|
||||||
|
|
||||||
|
// Copy results
|
||||||
|
result.Dummy = surfaceAtlasData.Dummy;
|
||||||
|
surfaceAtlasData.Result = result;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output)
|
||||||
|
{
|
||||||
|
GlobalSignDistanceFieldPass::BindingData bindingDataSDF;
|
||||||
|
BindingData bindingData;
|
||||||
|
if (GlobalSignDistanceFieldPass::Instance()->Render(renderContext, context, bindingDataSDF) || Render(renderContext, context, bindingData))
|
||||||
|
{
|
||||||
|
context->Draw(output, renderContext.Buffers->GBuffer0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROFILE_GPU_CPU("Global Surface Atlas Debug");
|
||||||
|
const Vector2 outputSize(output->Size());
|
||||||
|
if (_cb0)
|
||||||
|
{
|
||||||
|
Data0 data;
|
||||||
|
data.ViewWorldPos = renderContext.View.Position;
|
||||||
|
data.ViewNearPlane = renderContext.View.Near;
|
||||||
|
data.ViewFarPlane = renderContext.View.Far;
|
||||||
|
for (int32 i = 0; i < 4; i++)
|
||||||
|
data.ViewFrustumWorldRays[i] = Vector4(renderContext.List->FrustumCornersWs[i + 4], 0);
|
||||||
|
data.GlobalSDF = bindingDataSDF.GlobalSDF;
|
||||||
|
context->UpdateCB(_cb0, &data);
|
||||||
|
context->BindCB(0, _cb0);
|
||||||
|
}
|
||||||
|
for (int32 i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
context->BindSR(i, bindingDataSDF.Cascades[i]->ViewVolume());
|
||||||
|
context->BindSR(i + 4, bindingDataSDF.CascadeMips[i]->ViewVolume());
|
||||||
|
}
|
||||||
|
context->SetState(_psDebug);
|
||||||
|
context->SetRenderTarget(output->View());
|
||||||
|
context->SetViewportAndScissors(outputSize.X, outputSize.Y);
|
||||||
|
context->DrawFullscreenTriangle();
|
||||||
|
}
|
||||||
57
Source/Engine/Renderer/GlobalSurfaceAtlasPass.h
Normal file
57
Source/Engine/Renderer/GlobalSurfaceAtlasPass.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RendererPass.h"
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Global Surface Atlas rendering pass. Captures scene geometry into a single atlas texture which contains surface diffuse color, normal vector, emission light, and calculates direct+indirect lighting. Used by Global Illumination and Reflections.
|
||||||
|
/// </summary>
|
||||||
|
class FLAXENGINE_API GlobalSurfaceAtlasPass : public RendererPass<GlobalSurfaceAtlasPass>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Binding data for the GPU.
|
||||||
|
struct BindingData
|
||||||
|
{
|
||||||
|
GPUTexture* Dummy; // TODO: add textures
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _supported = false;
|
||||||
|
AssetReference<Shader> _shader;
|
||||||
|
GPUPipelineState* _psDebug = nullptr;
|
||||||
|
GPUConstantBuffer* _cb0 = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Renders the Global Surface Atlas.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderContext">The rendering context.</param>
|
||||||
|
/// <param name="context">The GPU context.</param>
|
||||||
|
/// <param name="result">The result Global Surface Atlas data for binding to the shaders.</param>
|
||||||
|
/// <returns>True if failed to render (platform doesn't support it, out of video memory, disabled feature or effect is not ready), otherwise false.</returns>
|
||||||
|
bool Render(RenderContext& renderContext, GPUContext* context, BindingData& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renders the debug view.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderContext">The rendering context.</param>
|
||||||
|
/// <param name="context">The GPU context.</param>
|
||||||
|
/// <param name="output">The output buffer.</param>
|
||||||
|
void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output);
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if COMPILE_WITH_DEV_ENV
|
||||||
|
void OnShaderReloading(Asset* obj);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
// [RendererPass]
|
||||||
|
String ToString() const override;
|
||||||
|
bool Init() override;
|
||||||
|
void Dispose() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// [RendererPass]
|
||||||
|
bool setupResources() override;
|
||||||
|
};
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "HistogramPass.h"
|
#include "HistogramPass.h"
|
||||||
#include "AtmospherePreCompute.h"
|
#include "AtmospherePreCompute.h"
|
||||||
#include "GlobalSignDistanceFieldPass.h"
|
#include "GlobalSignDistanceFieldPass.h"
|
||||||
|
#include "GlobalSurfaceAtlasPass.h"
|
||||||
#include "Utils/MultiScaler.h"
|
#include "Utils/MultiScaler.h"
|
||||||
#include "Utils/BitonicSort.h"
|
#include "Utils/BitonicSort.h"
|
||||||
#include "AntiAliasing/FXAA.h"
|
#include "AntiAliasing/FXAA.h"
|
||||||
@@ -83,6 +84,7 @@ bool RendererService::Init()
|
|||||||
PassList.Add(SMAA::Instance());
|
PassList.Add(SMAA::Instance());
|
||||||
PassList.Add(HistogramPass::Instance());
|
PassList.Add(HistogramPass::Instance());
|
||||||
PassList.Add(GlobalSignDistanceFieldPass::Instance());
|
PassList.Add(GlobalSignDistanceFieldPass::Instance());
|
||||||
|
PassList.Add(GlobalSurfaceAtlasPass::Instance());
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
PassList.Add(QuadOverdrawPass::Instance());
|
PassList.Add(QuadOverdrawPass::Instance());
|
||||||
#endif
|
#endif
|
||||||
@@ -352,11 +354,12 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
|
|||||||
|
|
||||||
// Debug drawing
|
// Debug drawing
|
||||||
if (renderContext.View.Mode == ViewMode::GlobalSDF)
|
if (renderContext.View.Mode == ViewMode::GlobalSDF)
|
||||||
{
|
|
||||||
GlobalSignDistanceFieldPass::Instance()->RenderDebug(renderContext, context, lightBuffer);
|
GlobalSignDistanceFieldPass::Instance()->RenderDebug(renderContext, context, lightBuffer);
|
||||||
}
|
else if (renderContext.View.Mode == ViewMode::GlobalSurfaceAtlas)
|
||||||
if (renderContext.View.Mode == ViewMode::Emissive ||
|
GlobalSurfaceAtlasPass::Instance()->RenderDebug(renderContext, context, lightBuffer);
|
||||||
renderContext.View.Mode == ViewMode::LightmapUVsDensity ||
|
if (renderContext.View.Mode == ViewMode::Emissive ||
|
||||||
|
renderContext.View.Mode == ViewMode::LightmapUVsDensity ||
|
||||||
|
renderContext.View.Mode == ViewMode::GlobalSurfaceAtlas ||
|
||||||
renderContext.View.Mode == ViewMode::GlobalSDF)
|
renderContext.View.Mode == ViewMode::GlobalSDF)
|
||||||
{
|
{
|
||||||
context->ResetRenderTarget();
|
context->ResetRenderTarget();
|
||||||
|
|||||||
5
Source/Shaders/GlobalSurfaceAtlas.hlsl
Normal file
5
Source/Shaders/GlobalSurfaceAtlas.hlsl
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#include "./Flax/Common.hlsl"
|
||||||
|
|
||||||
|
// TODO: implement Global Surface Atlas sampling
|
||||||
43
Source/Shaders/GlobalSurfaceAtlas.shader
Normal file
43
Source/Shaders/GlobalSurfaceAtlas.shader
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#include "./Flax/Common.hlsl"
|
||||||
|
#include "./Flax/Math.hlsl"
|
||||||
|
#include "./Flax/GlobalSurfaceAtlas.hlsl"
|
||||||
|
#include "./Flax/GlobalSignDistanceField.hlsl"
|
||||||
|
|
||||||
|
META_CB_BEGIN(0, Data)
|
||||||
|
float3 ViewWorldPos;
|
||||||
|
float ViewNearPlane;
|
||||||
|
float3 Padding00;
|
||||||
|
float ViewFarPlane;
|
||||||
|
float4 ViewFrustumWorldRays[4];
|
||||||
|
GlobalSDFData GlobalSDF;
|
||||||
|
META_CB_END
|
||||||
|
|
||||||
|
#ifdef _PS_Debug
|
||||||
|
|
||||||
|
Texture3D<float> GlobalSDFTex[4] : register(t0);
|
||||||
|
Texture3D<float> GlobalSDFMip[4] : register(t4);
|
||||||
|
|
||||||
|
// Pixel shader for Global Surface Atlas debug drawing
|
||||||
|
META_PS(true, FEATURE_LEVEL_SM5)
|
||||||
|
float4 PS_Debug(Quad_VS2PS input) : SV_Target
|
||||||
|
{
|
||||||
|
// Shot a ray from camera into the Global SDF
|
||||||
|
GlobalSDFTrace trace;
|
||||||
|
float3 viewRay = lerp(lerp(ViewFrustumWorldRays[3], ViewFrustumWorldRays[0], input.TexCoord.x), lerp(ViewFrustumWorldRays[2], ViewFrustumWorldRays[1], input.TexCoord.x), 1 - input.TexCoord.y).xyz;
|
||||||
|
viewRay = normalize(viewRay - ViewWorldPos);
|
||||||
|
trace.Init(ViewWorldPos, viewRay, ViewNearPlane, ViewFarPlane);
|
||||||
|
trace.NeedsHitNormal = true;
|
||||||
|
GlobalSDFHit hit = RayTraceGlobalSDF(GlobalSDF, GlobalSDFTex, GlobalSDFMip, trace);
|
||||||
|
if (!hit.IsHit())
|
||||||
|
return float4(float3(0.4f, 0.4f, 1.0f) * saturate(hit.StepsCount / 80.0f), 1);
|
||||||
|
|
||||||
|
// TODO: debug draw Surface Cache
|
||||||
|
|
||||||
|
// Debug draw SDF normals
|
||||||
|
float3 color = hit.HitNormal * 0.5f + 0.5f;
|
||||||
|
return float4(color, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user