ssao is now done in quarter resolution
- this means that we cannot share the depth pass between ssao and color passes, so all this code is removed, which simplify things a lot. - the depth pass code is moved into the ssao codepath since they're now intimately linked. - and finals ssao shader can't rely on frameUniform which is set up with the main buffer's size (instead of 1/4 res).
This commit is contained in:
committed by
Mathias Agopian
parent
43115e1f3b
commit
507aeb1e34
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "fg/FrameGraph.h"
|
||||
|
||||
#include "RenderPass.h"
|
||||
|
||||
#include "details/Material.h"
|
||||
#include "details/MaterialInstance.h"
|
||||
#include "generated/resources/materials.h"
|
||||
@@ -285,12 +287,40 @@ FrameGraphResource PostProcessManager::dynamicScaling(FrameGraph& fg,
|
||||
}
|
||||
|
||||
|
||||
FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, FrameGraphResource depth,
|
||||
View::AmbientOcclusionOptions const& options) noexcept {
|
||||
FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, RenderPass& pass,
|
||||
filament::Viewport const& svp, View::AmbientOcclusionOptions const& options) noexcept {
|
||||
|
||||
FEngine* engine = mEngine;
|
||||
Handle<HwRenderPrimitive> fullScreenRenderPrimitive = engine->getFullScreenRenderPrimitive();
|
||||
|
||||
// SSAO depth pass -- automatically culled if not used
|
||||
struct DepthPassData {
|
||||
FrameGraphResource depth;
|
||||
};
|
||||
|
||||
RenderPass::Command const* first = pass.getCommands().begin();
|
||||
RenderPass::Command const* last = pass.getCommands().end();
|
||||
|
||||
// SSAO generates its own depth path at 1/4 resolution
|
||||
auto& ssaoDepthPass = fg.addPass<DepthPassData>("SSAO Depth Pass",
|
||||
[&svp](FrameGraph::Builder& builder, DepthPassData& data) {
|
||||
|
||||
data.depth = builder.createTexture("Depth Buffer", {
|
||||
.width = svp.width / 2, .height = svp.height / 2,
|
||||
.format = TextureFormat::DEPTH24 });
|
||||
|
||||
data.depth = builder.useRenderTarget("SSAO Depth Target",
|
||||
{ .attachments.depth = data.depth }, TargetBufferFlags::DEPTH).depth;
|
||||
},
|
||||
[&pass, first, last](FrameGraphPassResources const& resources,
|
||||
DepthPassData const& data, DriverApi& driver) {
|
||||
assert(depthPassBegin && depthPassEnd);
|
||||
auto out = resources.getRenderTarget(data.depth);
|
||||
pass.execute(resources.getPassName(), out.target, out.params, first, last);
|
||||
});
|
||||
|
||||
FrameGraphResource depth = ssaoDepthPass.getData().depth;
|
||||
|
||||
struct SSAOPassData {
|
||||
FrameGraphResource depth;
|
||||
FrameGraphResource ssao;
|
||||
@@ -316,10 +346,13 @@ FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, FrameGraphResource d
|
||||
SSAOPassData const& data, DriverApi& driver) {
|
||||
auto depth = resources.getTexture(data.depth);
|
||||
auto ssao = resources.getRenderTarget(data.ssao);
|
||||
auto const& desc = resources.getDescriptor(data.ssao);
|
||||
|
||||
SamplerParams params;
|
||||
FMaterialInstance* const pInstance = mSSAOMaterialInstance;
|
||||
pInstance->setParameter("depth", depth, params);
|
||||
pInstance->setParameter("resolution",
|
||||
float4{ desc.width, desc.height, 1.0f / desc.width, 1.0f / desc.height });
|
||||
pInstance->setParameter("radius", data.options.radius);
|
||||
pInstance->setParameter("invRadiusSquared", 1.0f / (data.options.radius * data.options.radius));
|
||||
pInstance->setParameter("projectionScaleRadius", 500.0f * data.options.radius);
|
||||
|
||||
@@ -33,6 +33,7 @@ class FMaterial;
|
||||
class FMaterialInstance;
|
||||
class FEngine;
|
||||
class FView;
|
||||
class RenderPass;
|
||||
} // namespace details
|
||||
|
||||
class PostProcessManager {
|
||||
@@ -58,7 +59,8 @@ public:
|
||||
FrameGraph& fg, FrameGraphResource input) noexcept;
|
||||
|
||||
|
||||
FrameGraphResource ssao(FrameGraph& fg, FrameGraphResource depth,
|
||||
FrameGraphResource ssao(FrameGraph& fg, details::RenderPass& pass,
|
||||
filament::Viewport const& svp,
|
||||
View::AmbientOcclusionOptions const& options) noexcept;
|
||||
|
||||
backend::Handle<backend::HwTexture> getNoSSAOTexture() const {
|
||||
|
||||
@@ -225,7 +225,7 @@ public:
|
||||
void setRenderFlags(RenderFlags flags) noexcept;
|
||||
Command const* appendSortedCommands(CommandTypeFlags const commandTypeFlags) noexcept;
|
||||
void execute(const char* name,
|
||||
backend::Handle <backend::HwRenderTarget> renderTarget,
|
||||
backend::Handle<backend::HwRenderTarget> renderTarget,
|
||||
backend::RenderPassParams params,
|
||||
Command const* first, Command const* last) const noexcept;
|
||||
|
||||
|
||||
@@ -255,93 +255,26 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
view.commitUniforms(driver);
|
||||
|
||||
|
||||
RenderPass::CommandTypeFlags commandType = getCommandType(view.getDepthPrepass());
|
||||
|
||||
// It's unclear if it's always better to reuse the depth pass, as it has to be saved and
|
||||
// reloaded from memory -- as opposed to just regenerating it. Skinning is not an added concern,
|
||||
// because either way, we have to go through the geometry twice.
|
||||
constexpr bool REUSE_SSAO_DEPTH = true;
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
const bool useSSAO = view.getAmbientOcclusion() != View::AmbientOcclusion::NONE;
|
||||
Command const* depthPassBegin = nullptr;
|
||||
Command const* depthPassEnd = nullptr;
|
||||
Command const* colorPassBegin = nullptr;
|
||||
Command const* colorPassEnd = nullptr;
|
||||
|
||||
// We need an extra pass for SSAO if SSAO is enabled and:
|
||||
// - we don't want to reuse the regular depth path for SSAO, or
|
||||
// - we have MSAA (because SSAO is never done in MSAA), or
|
||||
// - we don't have a depth prepass in the first place
|
||||
const bool extraDepthPassForSSAO = useSSAO &&
|
||||
(!REUSE_SSAO_DEPTH || msaa > 1 || !(commandType & RenderPass::CommandTypeFlags::DEPTH));
|
||||
|
||||
// depth buffer is shared between SSAO and the color pass
|
||||
const bool sharedDepthPass = useSSAO && !extraDepthPassForSSAO;
|
||||
if (sharedDepthPass) {
|
||||
// When SSAO is active and it's sharing the depth pass with the color pass
|
||||
// (meaning that we don't have MSAA), we add alpha tested objects to the scene, they're
|
||||
// needed for SSAO and they won't hurt the color pass.
|
||||
commandType = RenderPass::CommandTypeFlags(commandType &
|
||||
~RenderPass::CommandTypeFlags::DEPTH_FILTER_ALPHA_MASKED_OBJECTS);
|
||||
}
|
||||
|
||||
if (extraDepthPassForSSAO) {
|
||||
// We don't have a depth prepass, so we need to generate the depth for the SSAO pass
|
||||
depthPassBegin = commands.end();
|
||||
depthPassEnd = pass.appendSortedCommands(RenderPass::CommandTypeFlags::DEPTH);
|
||||
}
|
||||
|
||||
// generate the normal commands
|
||||
colorPassBegin = commands.end();
|
||||
colorPassEnd = pass.appendSortedCommands(commandType);
|
||||
|
||||
if (sharedDepthPass) {
|
||||
assert(commandType & RenderPass::CommandTypeFlags::DEPTH);
|
||||
// isolate the depth-only commands
|
||||
depthPassBegin = commands.begin();
|
||||
depthPassEnd = std::partition_point(commands.begin(), commands.end(),
|
||||
[](Command const& command) {
|
||||
return (command.key & RenderPass::PASS_MASK) == uint64_t(RenderPass::Pass::DEPTH);
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
// SSAO depth pass -- automatically culled if not used
|
||||
struct DepthPassData {
|
||||
FrameGraphResource depth;
|
||||
};
|
||||
|
||||
auto& ssaoDepthPass = fg.addPass<DepthPassData>("SSAO Depth Pass",
|
||||
[&svp](FrameGraph::Builder& builder, DepthPassData& data) {
|
||||
|
||||
data.depth = builder.createTexture("Depth Buffer", {
|
||||
.width = svp.width, .height = svp.height,
|
||||
.format = TextureFormat::DEPTH24 });
|
||||
|
||||
data.depth = builder.useRenderTarget("SSAO Depth Target",
|
||||
{ .attachments.depth = data.depth }, TargetBufferFlags::DEPTH).depth;
|
||||
},
|
||||
[&pass, depthPassBegin, depthPassEnd](FrameGraphPassResources const& resources,
|
||||
DepthPassData const& data, DriverApi& driver) {
|
||||
assert(depthPassBegin && depthPassEnd);
|
||||
auto out = resources.getRenderTarget(data.depth);
|
||||
pass.execute(resources.getPassName(), out.target, out.params,
|
||||
depthPassBegin, depthPassEnd);
|
||||
});
|
||||
|
||||
FrameGraphResource depth = ssaoDepthPass.getData().depth;
|
||||
|
||||
// SSAO pass -- automatically culled if not used
|
||||
FrameGraphResource ssao = ppm.ssao(fg, depth, view.getAmbientOcclusionOptions());
|
||||
if (useSSAO) {
|
||||
pass.appendSortedCommands(RenderPass::CommandTypeFlags::DEPTH);
|
||||
}
|
||||
|
||||
FrameGraphResource ssao = ppm.ssao(fg, pass, svp, view.getAmbientOcclusionOptions());
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
// generate the normal commands
|
||||
RenderPass::CommandTypeFlags commandType = getCommandType(view.getDepthPrepass());
|
||||
Command const* colorPassBegin = commands.end();
|
||||
Command const* colorPassEnd = pass.appendSortedCommands(commandType);
|
||||
|
||||
// We only honor the view's color buffer clear flags, depth/stencil are handled by the framefraph
|
||||
TargetBufferFlags clearFlags = view.getClearFlags() & TargetBufferFlags::COLOR;
|
||||
if (!sharedDepthPass) {
|
||||
clearFlags |= TargetBufferFlags::DEPTH;
|
||||
}
|
||||
TargetBufferFlags clearFlags = view.getClearFlags() & TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH;
|
||||
|
||||
struct ColorPassData {
|
||||
FrameGraphResource color;
|
||||
@@ -350,7 +283,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
};
|
||||
|
||||
auto& colorPass = fg.addPass<ColorPassData>("Color Pass",
|
||||
[&svp, hdrFormat, colorPassNeedsDepthBuffer, msaa, clearFlags, depth, useSSAO, ssao, sharedDepthPass]
|
||||
[&svp, hdrFormat, colorPassNeedsDepthBuffer, msaa, clearFlags, useSSAO, ssao]
|
||||
(FrameGraph::Builder& builder, ColorPassData& data) {
|
||||
|
||||
if (useSSAO) {
|
||||
@@ -360,16 +293,12 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
data.color = builder.createTexture("Color Buffer",
|
||||
{ .width = svp.width, .height = svp.height, .format = hdrFormat, .samples = msaa });
|
||||
|
||||
if (sharedDepthPass) {
|
||||
data.depth = depth;
|
||||
} else {
|
||||
if (colorPassNeedsDepthBuffer) {
|
||||
data.depth = builder.createTexture("Depth Buffer", {
|
||||
.width = svp.width, .height = svp.height,
|
||||
.format = TextureFormat::DEPTH24,
|
||||
.samples = msaa
|
||||
});
|
||||
}
|
||||
if (colorPassNeedsDepthBuffer) {
|
||||
data.depth = builder.createTexture("Depth Buffer", {
|
||||
.width = svp.width, .height = svp.height,
|
||||
.format = TextureFormat::DEPTH24,
|
||||
.samples = msaa
|
||||
});
|
||||
}
|
||||
|
||||
FrameGraphRenderTarget::Descriptor desc{
|
||||
|
||||
@@ -6,6 +6,10 @@ material {
|
||||
name : depth,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : resolution
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : radius
|
||||
@@ -166,7 +170,7 @@ fragment {
|
||||
float ssRadius = max(1.0, tap.z * ssDiskRadius); // at least 1 pixel screen-space radius
|
||||
|
||||
ivec2 ssSamplePos = ssOrigin + ivec2(ssRadius * tap.xy);
|
||||
vec2 uvSamplePos = (vec2(ssSamplePos) + vec2(0.5)) * frameUniforms.resolution.zw;
|
||||
vec2 uvSamplePos = (vec2(ssSamplePos) + vec2(0.5)) * materialParams.resolution.zw;
|
||||
highp float occlusionDepth = linearizeDepth(texelFetch(materialParams_depth, clampToEdge(ssSamplePos), 0).r);
|
||||
highp vec3 p = computeViewSpacePositionFromDepth(uvSamplePos * 2.0 - 1.0, occlusionDepth);
|
||||
|
||||
@@ -211,7 +215,7 @@ fragment {
|
||||
}
|
||||
|
||||
normal = normalize(normal);
|
||||
ivec2 ssOrigin = ivec2(uv * frameUniforms.resolution.xy);
|
||||
ivec2 ssOrigin = ivec2(uv * materialParams.resolution.xy);
|
||||
float occlusion = 0.0;
|
||||
for (uint i = 0u; i < kSpiralSampleCount; i++) {
|
||||
occlusion += computeAmbientOcclusionSAO(i, ssDiskRadius, ssOrigin, origin, normal, noise);
|
||||
|
||||
@@ -6,6 +6,10 @@ material {
|
||||
name : depth,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : resolution
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : radius
|
||||
|
||||
Reference in New Issue
Block a user