From 583c1c07cfb76ef60ae315127bab80457f5808db Mon Sep 17 00:00:00 2001 From: Pixelflinger Date: Mon, 28 Sep 2020 18:05:40 -0700 Subject: [PATCH] SSCT optimizations and fixes - Use lower depth LOD as the cone radius increases. This is the same technique we use for SAO. The better cache access significantly improve performance. On a test on Pixel4 at 585MHz, SAO pass improves by 30%. This also helps the algorithm scale with the shadow distance. - Shadow direction/length no longer dependent on aspect-ratio and camera orientation. This is fixed by doing all the computations in screen-space instead of normalized screen space. - Shadow parameters are no longer dependent on the field of view. - Also rename dominantLightShadowing.fs to ssct.fs - remove zoom parameter, it wasn't very useful. --- .../filament-android/src/main/cpp/View.cpp | 3 +- .../com/google/android/filament/View.java | 13 ++---- filament/CMakeLists.txt | 2 +- filament/include/filament/View.h | 5 +-- filament/src/PostProcessManager.cpp | 13 +++--- filament/src/details/View.h | 1 - filament/src/materials/ssao/sao.mat | 41 +++++++++++-------- .../{dominantLightShadowing.fs => ssct.fs} | 33 +++++++++------ libs/viewer/src/SimpleViewer.cpp | 1 - samples/material_sandbox.cpp | 1 - 10 files changed, 58 insertions(+), 55 deletions(-) rename filament/src/materials/ssao/{dominantLightShadowing.fs => ssct.fs} (86%) diff --git a/android/filament-android/src/main/cpp/View.cpp b/android/filament-android/src/main/cpp/View.cpp index 2f2f897dd3..ebcb094541 100644 --- a/android/filament-android/src/main/cpp/View.cpp +++ b/android/filament-android/src/main/cpp/View.cpp @@ -217,7 +217,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_View_nSetSSCTOptions(JNIEnv *, jclass, jlong nativeView, jfloat ssctLightConeRad, jfloat ssctStartTraceDistance, jfloat ssctContactDistanceMax, jfloat ssctIntensity, jfloat ssctLightDirX, jfloat ssctLightDirY, jfloat ssctLightDirZ, - jfloat ssctDepthBias, jfloat ssctDepthSlopeBias, jfloat ssctScale, jint ssctSampleCount, + jfloat ssctDepthBias, jfloat ssctDepthSlopeBias, jint ssctSampleCount, jint ssctRayCount, jboolean ssctEnabled) { View* view = (View*) nativeView; View::AmbientOcclusionOptions options = view->getAmbientOcclusionOptions(); @@ -228,7 +228,6 @@ Java_com_google_android_filament_View_nSetSSCTOptions(JNIEnv *, jclass, jlong na options.ssct.lightDirection = math::float3{ ssctLightDirX, ssctLightDirY, ssctLightDirZ }; options.ssct.depthBias = ssctDepthBias; options.ssct.depthSlopeBias = ssctDepthSlopeBias; - options.ssct.scale = ssctScale; options.ssct.sampleCount = (uint8_t)ssctSampleCount; options.ssct.rayCount = (uint8_t)ssctRayCount; options.ssct.enabled = (bool)ssctEnabled; diff --git a/android/filament-android/src/main/java/com/google/android/filament/View.java b/android/filament-android/src/main/java/com/google/android/filament/View.java index 18dd158194..82a42af400 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/View.java +++ b/android/filament-android/src/main/java/com/google/android/filament/View.java @@ -238,17 +238,12 @@ public class View { /** * Depth bias in world units (mitigate self shadowing) */ - public float ssctDepthBias = 0.1f; + public float ssctDepthBias = 0.01f; /** * Depth slope bias (mitigate self shadowing) */ - public float ssctDepthSlopeBias = 0.1f; - - /** - * Shadows scaling. - */ - public float ssctScale = 1.0f; + public float ssctDepthSlopeBias = 0.01f; /** * Tracing sample count, between 1 and 255. This affects the quality as well as the @@ -1184,7 +1179,7 @@ public class View { options.enabled, options.minHorizonAngleRad); nSetSSCTOptions(getNativeObject(), options.ssctLightConeRad, options.ssctStartTraceDistance, options.ssctContactDistanceMax, options.ssctIntensity, options.ssctLightDirection[0], options.ssctLightDirection[1], options.ssctLightDirection[2], - options.ssctDepthBias, options.ssctDepthSlopeBias, options.ssctScale, options.ssctSampleCount, + options.ssctDepthBias, options.ssctDepthSlopeBias, options.ssctSampleCount, options.ssctRayCount, options.ssctEnabled); } @@ -1350,7 +1345,7 @@ public class View { private static native void nSetAmbientOcclusion(long nativeView, int ordinal); private static native int nGetAmbientOcclusion(long nativeView); private static native void nSetAmbientOcclusionOptions(long nativeView, float radius, float bias, float power, float resolution, float intensity, int quality, int lowPassFilter, int upsampling, boolean enabled, float minHorizonAngleRad); - private static native void nSetSSCTOptions(long nativeView, float ssctLightConeRad, float ssctStartTraceDistance, float ssctContactDistanceMax, float ssctIntensity, float v, float v1, float v2, float ssctDepthBias, float ssctDepthSlopeBias, float ssctScale, int ssctSampleCount, int ssctRayCount, boolean ssctEnabled); + private static native void nSetSSCTOptions(long nativeView, float ssctLightConeRad, float ssctStartTraceDistance, float ssctContactDistanceMax, float ssctIntensity, float v, float v1, float v2, float ssctDepthBias, float ssctDepthSlopeBias, int ssctSampleCount, int ssctRayCount, boolean ssctEnabled); private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, float anamorphism, int levels, int blendMode, boolean threshold, boolean enabled, float highlight); private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, boolean enabled); private static native void nSetBlendMode(long nativeView, int blendMode); diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index f33fa9a5a4..3132507ecc 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -298,7 +298,7 @@ add_custom_command( add_custom_command( OUTPUT "${MATERIAL_DIR}/sao.filamat" - DEPENDS src/materials/ssao/dominantLightShadowing.fs + DEPENDS src/materials/ssao/ssct.fs APPEND ) diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index 30ae51c704..6bbf1be3ea 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -235,9 +235,8 @@ public: float contactDistanceMax = 1.0f; //!< max distance shadows are cast float intensity = 0.8f; //!< intensity math::float3 lightDirection{ 0, -1, 0 }; //!< light direction - float depthBias = 0.1f; //!< depth bias in world units (mitigate self shadowing) - float depthSlopeBias = 0.1f; //!< depth slope bias (mitigate self shadowing) - float scale = 1.0f; //!< cast shadows scaling + float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing) + float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing) uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255 uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255 bool enabled = false; //!< enables or disables SSCT diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index a546cef035..ddd0d51211 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -473,7 +473,6 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( 0.5f * cameraInfo.projection[0].x * desc.width, 0.5f * cameraInfo.projection[1].y * desc.height); - // Where the falloff function peaks const float peak = 0.1f * options.radius; const float intensity = (f::TAU * peak) * options.intensity; @@ -483,9 +482,9 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( const auto invProjection = inverse(cameraInfo.projection); const float inc = (1.0f / (sampleCount - 0.5f)) * spiralTurns * f::TAU; - constexpr mat4 screenFromClipMatrix{ mat4::row_major_init{ - 0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, + const mat4 screenFromClipMatrix{ mat4::row_major_init{ + 0.5 * desc.width, 0.0, 0.0, 0.5 * desc.width, + 0.0, 0.5 * desc.height, 0.0, 0.5 * desc.height, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0 }}; @@ -502,11 +501,12 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( 1.0f / (options.radius * options.radius)); mi->setParameter("minHorizonAngleSineSquared", std::pow(std::sin(options.minHorizonAngleRad), 2.0f)); + mi->setParameter("projectionScale", + projectionScale); mi->setParameter("projectionScaleRadius", projectionScale * options.radius); mi->setParameter("depthParams", cameraInfo.projection[3][2] * 0.5f); - mi->setParameter("positionParams", float2{ invProjection[0][0], invProjection[1][1] } * 2.0f); mi->setParameter("peak2", peak * peak); @@ -522,7 +522,7 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( mi->setParameter("ssctConeTraceParams", float4{ options.ssct.enabled ? std::tan(options.ssct.lightConeRad * 0.5f) : 0.0f, std::sin(options.ssct.lightConeRad * 0.5f), - options.ssct.startTraceDistance, + options.ssct.startTraceDistance * projectionScale, 1.0f / options.ssct.contactDistanceMax }); @@ -539,7 +539,6 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOcclusion( mi->setParameter("ssctVsLightDirection", -l); mi->setParameter("ssctDepthBias", float2{ options.ssct.depthBias, options.ssct.depthSlopeBias }); - mi->setParameter("ssctInvZoom", options.ssct.scale); mi->setParameter("ssctSampleCount", uint32_t(options.ssct.sampleCount)); mi->setParameter("ssctRayCount", float2{ options.ssct.rayCount, 1.0 / options.ssct.rayCount }); diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 7704cbbf2d..8bde00d7aa 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -302,7 +302,6 @@ public: options.ssct.lightDirection = normalize(options.ssct.lightDirection); options.ssct.depthBias = std::max(0.0f, options.ssct.depthBias); options.ssct.depthSlopeBias = std::max(0.0f, options.ssct.depthSlopeBias); - options.ssct.scale = std::max(0.0f, options.ssct.scale); options.ssct.sampleCount = math::clamp((unsigned)options.ssct.sampleCount, 1u, 255u); options.ssct.rayCount = math::clamp((unsigned)options.ssct.rayCount, 1u, 255u); mAmbientOcclusionOptions = options; diff --git a/filament/src/materials/ssao/sao.mat b/filament/src/materials/ssao/sao.mat index 6c0336cfa5..5a0a83145b 100644 --- a/filament/src/materials/ssao/sao.mat +++ b/filament/src/materials/ssao/sao.mat @@ -16,13 +16,13 @@ material { precision: high }, { - type : float, - name : depthParams, + type : float2, + name : positionParams, precision: high }, { - type : float2, - name : positionParams, + type : float, + name : depthParams, precision: high }, { @@ -37,6 +37,10 @@ material { type : float, name : peak2 }, + { + type : float, + name : projectionScale + }, { type : float, name : projectionScaleRadius @@ -53,14 +57,14 @@ material { type : float, name : intensity }, - { - type : float2, - name : sampleCount - }, { type : float, name : spiralTurns }, + { + type : float2, + name : sampleCount + }, { type : float2, name : angleIncCosSin @@ -73,6 +77,10 @@ material { type : int, name : maxLevel }, + { + type : float2, + name : reserved + }, { type : float4, name : ssctConeTraceParams @@ -90,16 +98,12 @@ material { name : ssctDepthBias }, { - type : float, - name : ssctInvZoom + type : float2, + name : ssctRayCount }, { type : uint, name : ssctSampleCount - }, - { - type : float2, - name : ssctRayCount } ], variables : [ @@ -118,10 +122,9 @@ vertex { fragment { #include "ssaoUtils.fs" - #include "dominantLightShadowing.fs" + #include "ssct.fs" const float kLog2LodRate = 3.0; - const float kEdgeDistance = 0.0625; // this shouldn't be hardcoded vec2 sq(const vec2 a) { return a * a; @@ -253,18 +256,20 @@ fragment { float dominantLightShadowing(highp vec2 uv, highp vec3 origin, vec3 normal) { ConeTraceSetup cone; - cone.ssStartPos = uv; + cone.ssStartPos = uv * materialParams.resolution.xy; cone.vsStartPos = origin; cone.vsNormal = normal; cone.screenFromViewMatrix = materialParams.screenFromViewMatrix; cone.depthParams = materialParams.depthParams; cone.vsConeDirection = materialParams.ssctVsLightDirection; + cone.projectionScale = materialParams.projectionScale; + cone.resolution = materialParams.resolution; cone.coneTraceParams = materialParams.ssctConeTraceParams; cone.intensity = materialParams.ssctIntensity; - cone.invZoom = materialParams.ssctInvZoom; cone.depthBias = materialParams.ssctDepthBias.x; cone.slopeScaledDepthBias = materialParams.ssctDepthBias.y; cone.sampleCount = materialParams.ssctSampleCount; + cone.maxLevel = float(materialParams.maxLevel); float occlusion = 0.0; for (float i = 1.0; i <= materialParams.ssctRayCount.x; i += 1.0) { cone.jitterOffset.x = random(gl_FragCoord.xy * i) * 2.0 - 1.0; // direction diff --git a/filament/src/materials/ssao/dominantLightShadowing.fs b/filament/src/materials/ssao/ssct.fs similarity index 86% rename from filament/src/materials/ssao/dominantLightShadowing.fs rename to filament/src/materials/ssao/ssct.fs index 13c97501de..944af1ec90 100644 --- a/filament/src/materials/ssao/dominantLightShadowing.fs +++ b/filament/src/materials/ssao/ssct.fs @@ -5,20 +5,28 @@ #include "ssaoUtils.fs" +const float kSSCTLog2LodRate = 4.0; + struct ConeTraceSetup { - // runtime parameters + // fragment info highp vec2 ssStartPos; highp vec3 vsStartPos; vec3 vsNormal; - highp mat4 screenFromViewMatrix; - vec2 jitterOffset; // (x = direction offset, y = step offset) - highp float depthParams; + + // light (cone) info vec3 vsConeDirection; + vec4 coneTraceParams; // { tan(angle), sin(angle), start trace distance, inverse max contact distance } + vec2 jitterOffset; // (x = direction offset, y = step offset) + + // scene infos + highp mat4 screenFromViewMatrix; + highp float depthParams; + float projectionScale; + vec4 resolution; + float maxLevel; // artistic/quality parameters - vec4 coneTraceParams; // { tan(angle), sin(angle), start trace distance, inverse max contact distance } float intensity; - float invZoom; float depthBias; float slopeScaledDepthBias; uint sampleCount; @@ -50,16 +58,16 @@ float coneTraceOcclusion(in ConeTraceSetup setup, const sampler2D depthTexture) highp vec2 ssEndPos = (setup.screenFromViewMatrix * vec4(vsEndPos, 1.0)).xy * ssEndPosInvW; // cone trace direction in screen-space - float ssConeLength = length(ssEndPos.xy - ssStartPos); + float ssConeLength = length(ssEndPos - ssStartPos); float ssInvConeLength = 1.0 / ssConeLength; - vec2 ssConeDirection = (ssEndPos.xy - ssStartPos) * ssInvConeLength; + vec2 ssConeDirection = (ssEndPos - ssStartPos) * ssInvConeLength; // direction perpendicular to cone trace direction vec2 perpConeDir = vec2(ssConeDirection.y, -ssConeDirection.x); // avoid self-occlusion and reduce banding artifacts by normal variation vec3 vsViewVector = normalize(vsStartPos); - float minTraceDistance = (1.0 - abs(dot(setup.vsNormal, vsViewVector))) * 0.005; + float minTraceDistance = (1.0 - abs(dot(setup.vsNormal, vsViewVector))) * setup.projectionScale * 0.005; // init trace distance and sample radius highp float invLinearDepth = 1.0 / -setup.vsStartPos.z; @@ -67,7 +75,7 @@ float coneTraceOcclusion(in ConeTraceSetup setup, const sampler2D depthTexture) float ssSampleRadius = setup.coneTraceParams.y * ssTracedDistance; float ssEndRadius = setup.coneTraceParams.y * ssConeLength; - float vsEndRadius = ssEndRadius * setup.invZoom * invLinearDepth * ssEndPosW; + float vsEndRadius = ssEndRadius * (1.0 / setup.projectionScale) * invLinearDepth * ssEndPosW; // calculate depth bias float vsDepthBias = saturate(1.0 - NoL) * setup.slopeScaledDepthBias + setup.depthBias; @@ -85,9 +93,10 @@ float coneTraceOcclusion(in ConeTraceSetup setup, const sampler2D depthTexture) float ssJitteredSampleRadius = setup.jitterOffset.x * setup.coneTraceParams.x * ssJitteredTracedDistance; ssTracedDistance += ssStepDistance; - // sample depth buffer + // sample depth buffer, using lower LOD as the radius (i.e. distance from origin) grows highp vec2 ssSamplePos = perpConeDir * ssJitteredSampleRadius + ssConeDirection * ssJitteredTracedDistance + ssStartPos; - float vsSampleDepthLinear = -sampleDepthLinear(depthTexture, ssSamplePos, 0.0, setup.depthParams); + float level = clamp(floor(log2(ssJitteredTracedDistance)) - kSSCTLog2LodRate, 0.0, setup.maxLevel); + float vsSampleDepthLinear = -sampleDepthLinear(depthTexture, ssSamplePos * setup.resolution.zw, level, setup.depthParams); // calculate depth of cone center float ratio = ssJitteredTracedDistance * ssInvConeLength; diff --git a/libs/viewer/src/SimpleViewer.cpp b/libs/viewer/src/SimpleViewer.cpp index 3bf521bf88..a6cbdae544 100644 --- a/libs/viewer/src/SimpleViewer.cpp +++ b/libs/viewer/src/SimpleViewer.cpp @@ -319,7 +319,6 @@ void SimpleViewer::updateUserInterface() { ImGui::SliderFloat("Intensity##dls", &ssao.ssct.intensity, 0.0f, 10.0f); ImGui::SliderFloat("Depth bias", &ssao.ssct.depthBias, 0.0f, 1.0f); ImGui::SliderFloat("Depth slope bias", &ssao.ssct.depthSlopeBias, 0.0f, 1.0f); - ImGui::SliderFloat("Scale", &ssao.ssct.scale, 0.0f, 10.0f); ImGui::SliderInt("Sample Count", &sampleCount, 1, 32); ImGuiExt::DirectionWidget("Direction##dls", ssao.ssct.lightDirection.v); ssao.ssct.sampleCount = sampleCount; diff --git a/samples/material_sandbox.cpp b/samples/material_sandbox.cpp index e5cdd47860..e0138c08be 100644 --- a/samples/material_sandbox.cpp +++ b/samples/material_sandbox.cpp @@ -628,7 +628,6 @@ static void gui(filament::Engine* engine, filament::View*) { ImGui::SliderFloat("Intensity##dls", ¶ms.ssaoOptions.ssct.intensity, 0.0f, 10.0f); ImGui::SliderFloat("Depth bias", ¶ms.ssaoOptions.ssct.depthBias, 0.0f, 1.0f); ImGui::SliderFloat("Depth slope bias", ¶ms.ssaoOptions.ssct.depthSlopeBias, 0.0f, 1.0f); - ImGui::SliderFloat("Scale", ¶ms.ssaoOptions.ssct.scale, 0.0f, 10.0f); ImGui::SliderInt("Sample Count", &sampleCount, 1, 32); ImGui::SliderInt("Ray Count", &rayCount, 1, 8); ImGuiExt::DirectionWidget("Direction##dls", params.ssaoOptions.ssct.lightDirection.v);