SAO now uses a hierarchical depth to improve performance
- we generate LODs for the depth map using the framegraph - these LODs are used in the SAO shader to improve data access locality
This commit is contained in:
committed by
Mathias Agopian
parent
122eb8c82e
commit
9befaeb3ae
@@ -124,6 +124,7 @@ set(PRIVATE_HDRS
|
||||
|
||||
set(MATERIAL_SRCS
|
||||
src/materials/defaultMaterial.mat
|
||||
src/materials/mipmapDepth.mat
|
||||
src/materials/skybox.mat
|
||||
src/materials/skyboxRGBM.mat
|
||||
src/materials/sao.mat
|
||||
|
||||
@@ -215,15 +215,15 @@ void FEngine::init() {
|
||||
.intensity(1.0f)
|
||||
.build(*this));
|
||||
|
||||
mPostProcessManager.init(*this);
|
||||
mLightManager.init(*this);
|
||||
mDFG.reset(new DFG(*this));
|
||||
|
||||
// Always initialize the default material, most materials' depth shaders fallback on it.
|
||||
mDefaultMaterial = upcast(
|
||||
FMaterial::DefaultMaterialBuilder()
|
||||
.package(MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE)
|
||||
.build(*const_cast<FEngine*>(this)));
|
||||
|
||||
mPostProcessManager.init(*this);
|
||||
mLightManager.init(*this);
|
||||
mDFG.reset(new DFG(*this));
|
||||
}
|
||||
|
||||
FEngine::~FEngine() noexcept {
|
||||
|
||||
@@ -62,10 +62,13 @@ void PostProcessManager::init(FEngine& engine) noexcept {
|
||||
|
||||
mSSAOMaterial = upcast(Material::Builder().package(
|
||||
MATERIALS_SAO_DATA, MATERIALS_SAO_SIZE).build(engine));
|
||||
|
||||
mSSAOMaterialInstance = mSSAOMaterial->getDefaultInstance();
|
||||
|
||||
mSSAOProgram = mSSAOMaterial->getProgram(0);
|
||||
|
||||
mMipmapDepthMaterial = upcast(Material::Builder().package(
|
||||
MATERIALS_MIPMAPDEPTH_DATA, MATERIALS_MIPMAPDEPTH_SIZE).build(engine));
|
||||
mMipmapDepthMaterialInstance = mMipmapDepthMaterial->getDefaultInstance();
|
||||
mMipmapDepthProgram = mMipmapDepthMaterial->getProgram(0);
|
||||
}
|
||||
|
||||
void PostProcessManager::terminate(backend::DriverApi& driver) noexcept {
|
||||
@@ -307,12 +310,16 @@ FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, RenderPass& pass,
|
||||
RenderPass::Command const* first = pass.getCommands().begin();
|
||||
RenderPass::Command const* last = pass.getCommands().end();
|
||||
|
||||
// We limit the level size to 32 pixels (which is where the -5 comes from)
|
||||
const size_t levelCount = std::max(1, std::ilogbf(std::max(svp.width, svp.height) / 2) + 1 - 5);
|
||||
|
||||
// SSAO generates its own depth path at 1/4 resolution
|
||||
auto& ssaoDepthPass = fg.addPass<DepthPassData>("SSAO Depth Pass",
|
||||
[&svp](FrameGraph::Builder& builder, DepthPassData& data) {
|
||||
[&svp, levelCount](FrameGraph::Builder& builder, DepthPassData& data) {
|
||||
|
||||
data.depth = builder.createTexture("Depth Buffer", {
|
||||
.width = svp.width / 2, .height = svp.height / 2,
|
||||
.levels = uint8_t(levelCount),
|
||||
.format = TextureFormat::DEPTH24 });
|
||||
|
||||
data.depth = builder.useRenderTarget("SSAO Depth Target",
|
||||
@@ -326,6 +333,49 @@ FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, RenderPass& pass,
|
||||
|
||||
FrameGraphResource depth = ssaoDepthPass.getData().depth;
|
||||
|
||||
// The first mip already exists, so we process n-1 lods
|
||||
for (size_t level = 0; level < levelCount - 1; level++) {
|
||||
struct DepthMipData {
|
||||
FrameGraphResource in;
|
||||
FrameGraphResource out;
|
||||
};
|
||||
|
||||
auto& depthMipmappass = fg.addPass<DepthMipData>("Depth Mipmap Pass",
|
||||
[depth, level](FrameGraph::Builder& builder, DepthMipData& data) {
|
||||
const char* name = builder.getName(depth);
|
||||
data.in = builder.useRenderTarget(name, {
|
||||
.attachments.depth = {
|
||||
depth, uint8_t(level), FrameGraphRenderTarget::Attachments::READ }}).depth;
|
||||
|
||||
data.out = builder.useRenderTarget(name, {
|
||||
.attachments.depth = {
|
||||
depth, uint8_t(level + 1), FrameGraphRenderTarget::Attachments::WRITE }}).depth;
|
||||
},
|
||||
[this, fullScreenRenderPrimitive, level](FrameGraphPassResources const& resources,
|
||||
DepthMipData const& data, DriverApi& driver) {
|
||||
|
||||
auto in = resources.getTexture(data.in);
|
||||
auto out = resources.getRenderTarget(data.out, level + 1u);
|
||||
|
||||
SamplerParams params;
|
||||
FMaterialInstance* const pInstance = mMipmapDepthMaterialInstance;
|
||||
pInstance->setParameter("depth", in, params);
|
||||
pInstance->setParameter("level", uint32_t(level));
|
||||
pInstance->commit(driver);
|
||||
pInstance->use(driver);
|
||||
|
||||
PipelineState pipeline;
|
||||
pipeline.program = mMipmapDepthProgram;
|
||||
pipeline.rasterState = mMipmapDepthMaterial->getRasterState();
|
||||
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
driver.draw(pipeline, fullScreenRenderPrimitive);
|
||||
driver.endRenderPass();
|
||||
});
|
||||
|
||||
depth = depthMipmappass.getData().out;
|
||||
}
|
||||
|
||||
struct SSAOPassData {
|
||||
FrameGraphResource depth;
|
||||
FrameGraphResource ssao;
|
||||
@@ -349,7 +399,7 @@ FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, RenderPass& pass,
|
||||
.attachments.depth = { data.depth, FrameGraphRenderTarget::Attachments::READ }
|
||||
}, TargetBufferFlags::NONE).color;
|
||||
},
|
||||
[this, fullScreenRenderPrimitive](FrameGraphPassResources const& resources,
|
||||
[this, levelCount, fullScreenRenderPrimitive](FrameGraphPassResources const& resources,
|
||||
SSAOPassData const& data, DriverApi& driver) {
|
||||
auto depth = resources.getTexture(data.depth);
|
||||
auto ssao = resources.getRenderTarget(data.ssao);
|
||||
@@ -365,6 +415,7 @@ FrameGraphResource PostProcessManager::ssao(FrameGraph& fg, RenderPass& pass,
|
||||
pInstance->setParameter("projectionScaleRadius", 500.0f * data.options.radius);
|
||||
pInstance->setParameter("bias", data.options.bias);
|
||||
pInstance->setParameter("power", data.options.power);
|
||||
pInstance->setParameter("maxLevel", uint32_t(levelCount - 1));
|
||||
pInstance->commit(driver);
|
||||
pInstance->use(driver);
|
||||
|
||||
|
||||
@@ -79,6 +79,10 @@ private:
|
||||
details::FMaterialInstance* mSSAOMaterialInstance = nullptr;
|
||||
backend::Handle<backend::HwProgram> mSSAOProgram;
|
||||
|
||||
details::FMaterial* mMipmapDepthMaterial = nullptr;
|
||||
details::FMaterialInstance* mMipmapDepthMaterialInstance = nullptr;
|
||||
backend::Handle<backend::HwProgram> mMipmapDepthProgram;
|
||||
|
||||
backend::Handle<backend::HwTexture> mNoSSAOTexture;
|
||||
};
|
||||
|
||||
|
||||
@@ -639,7 +639,7 @@ FrameGraphResource::Descriptor const& FrameGraphPassResources::getDescriptor(
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
FrameGraph::FrameGraph()
|
||||
: mArena("FrameGraph Arena", 16384), // TODO: the Area will eventually come from outside
|
||||
: mArena("FrameGraph Arena", 32768), // TODO: the Area will eventually come from outside
|
||||
mPassNodes(mArena),
|
||||
mResourceNodes(mArena),
|
||||
mRenderTargets(mArena),
|
||||
|
||||
46
filament/src/materials/mipmapDepth.mat
Normal file
46
filament/src/materials/mipmapDepth.mat
Normal file
@@ -0,0 +1,46 @@
|
||||
material {
|
||||
name : mipmapDepth,
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
name : depth,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : level
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
],
|
||||
vertexDomain : device,
|
||||
depthWrite : true,
|
||||
depthCulling : false,
|
||||
shadingModel : unlit,
|
||||
variantFilter : [ skinning ],
|
||||
culling: none
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
|
||||
int level = materialParams.level;
|
||||
ivec2 xy = ivec2(gl_FragCoord.xy) * 2;
|
||||
highp float d00 = texelFetch(materialParams_depth, xy + ivec2(0, 0), level).r;
|
||||
highp float d10 = texelFetch(materialParams_depth, xy + ivec2(1, 0), level).r;
|
||||
highp float d01 = texelFetch(materialParams_depth, xy + ivec2(0, 1), level).r;
|
||||
highp float d11 = texelFetch(materialParams_depth, xy + ivec2(1, 1), level).r;
|
||||
|
||||
gl_FragDepth =
|
||||
|
||||
// conservative occlusion
|
||||
//max(d00, max(d01, max(d10, d11)));
|
||||
|
||||
// conservative visibility
|
||||
//min(d00, min(d01, min(d10, d11)));
|
||||
|
||||
// arithmetic mean: preserve screen-space area
|
||||
(d00 + d01 + d10 + d11) * 0.25;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
material {
|
||||
name : ssao,
|
||||
name : sao,
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
@@ -29,6 +29,10 @@ material {
|
||||
{
|
||||
type : float,
|
||||
name : power
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : maxLevel
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
@@ -53,6 +57,8 @@ vertex {
|
||||
}
|
||||
|
||||
fragment {
|
||||
#define LOG2_LOD_RATE 4
|
||||
|
||||
#define NOISE_NONE 0
|
||||
#define NOISE_PATTERN 1
|
||||
#define NOISE_RANDOM 2
|
||||
@@ -162,8 +168,8 @@ fragment {
|
||||
return vec3(M * kSipralSamples[i].xy, radius * radius);
|
||||
}
|
||||
|
||||
ivec2 clampToEdge(ivec2 uv) {
|
||||
return clamp(uv, ivec2(0), textureSize(materialParams_depth, 0) - ivec2(1));
|
||||
ivec2 clampToEdge(ivec2 uv, int level) {
|
||||
return clamp(uv, ivec2(0), textureSize(materialParams_depth, level) - ivec2(1));
|
||||
}
|
||||
|
||||
float computeAmbientOcclusionSAO(uint i, float ssDiskRadius, const ivec2 ssOrigin, const highp vec3 origin, const vec3 normal, const vec3 noise) {
|
||||
@@ -172,7 +178,10 @@ fragment {
|
||||
|
||||
ivec2 ssSamplePos = ssOrigin + ivec2(ssRadius * tap.xy);
|
||||
vec2 uvSamplePos = (vec2(ssSamplePos) + vec2(0.5)) * materialParams.resolution.zw;
|
||||
highp float occlusionDepth = linearizeDepth(texelFetch(materialParams_depth, clampToEdge(ssSamplePos), 0).r);
|
||||
|
||||
// level = floor(log2(screenSpaceRadius/rate)))
|
||||
int level = clamp(int(floor(log2(ssRadius))) - LOG2_LOD_RATE, 0, materialParams.maxLevel);
|
||||
highp float occlusionDepth = linearizeDepth(texelFetch(materialParams_depth, clampToEdge(ssSamplePos >> level, level), level).r);
|
||||
highp vec3 p = computeViewSpacePositionFromDepth(uvSamplePos * 2.0 - 1.0, occlusionDepth);
|
||||
|
||||
// now we have the sample, compute AO
|
||||
|
||||
@@ -29,6 +29,10 @@ material {
|
||||
{
|
||||
type : float,
|
||||
name : power
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : maxLevel
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
|
||||
Reference in New Issue
Block a user