From 81a2d70251d70aa93d79ec591c48da97c8ecdbd7 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Wed, 4 Mar 2020 11:59:25 -0800 Subject: [PATCH] Use array texture for shadow maps (#2199) --- filament/src/ShadowMap.cpp | 2 +- libs/filabridge/src/SibGenerator.cpp | 14 ++--- shaders/src/light_directional.fs | 2 +- shaders/src/shading_unlit.fs | 2 +- shaders/src/shadowing.fs | 82 ++++++++++++++-------------- 5 files changed, 51 insertions(+), 51 deletions(-) diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index 1190193ba4..658404c7e6 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -128,7 +128,7 @@ void ShadowMap::prepare(DriverApi& driver, SamplerGroup& sb) noexcept { } mShadowMapHandle = driver.createTexture( - SamplerType::SAMPLER_2D, 1, format, 1, dim, dim, 1, + SamplerType::SAMPLER_2D_ARRAY, 1, format, 1, dim, dim, 1, TextureUsage::DEPTH_ATTACHMENT | TextureUsage::SAMPLEABLE); mShadowMapRenderTarget = driver.createRenderTarget( diff --git a/libs/filabridge/src/SibGenerator.cpp b/libs/filabridge/src/SibGenerator.cpp index 058f830a5b..ba43137108 100644 --- a/libs/filabridge/src/SibGenerator.cpp +++ b/libs/filabridge/src/SibGenerator.cpp @@ -30,13 +30,13 @@ SamplerInterfaceBlock const& SibGenerator::getPerViewSib() noexcept { // TODO: ideally we'd want this to be constexpr, this is a compile time structure static SamplerInterfaceBlock sib = SamplerInterfaceBlock::Builder() .name("Light") - .add("shadowMap", Type::SAMPLER_2D, Format::SHADOW,Precision::LOW) - .add("records", Type::SAMPLER_2D, Format::UINT, Precision::MEDIUM) - .add("froxels", Type::SAMPLER_2D, Format::UINT, Precision::MEDIUM) - .add("iblDFG", Type::SAMPLER_2D, Format::FLOAT, Precision::MEDIUM) - .add("iblSpecular", Type::SAMPLER_CUBEMAP, Format::FLOAT, Precision::MEDIUM) - .add("ssao", Type::SAMPLER_2D, Format::FLOAT, Precision::MEDIUM) - .add("ssr", Type::SAMPLER_2D, Format::FLOAT, Precision::MEDIUM) + .add("shadowMap", Type::SAMPLER_2D_ARRAY, Format::SHADOW, Precision::LOW) + .add("records", Type::SAMPLER_2D, Format::UINT, Precision::MEDIUM) + .add("froxels", Type::SAMPLER_2D, Format::UINT, Precision::MEDIUM) + .add("iblDFG", Type::SAMPLER_2D, Format::FLOAT, Precision::MEDIUM) + .add("iblSpecular", Type::SAMPLER_CUBEMAP, Format::FLOAT, Precision::MEDIUM) + .add("ssao", Type::SAMPLER_2D, Format::FLOAT, Precision::MEDIUM) + .add("ssr", Type::SAMPLER_2D, Format::FLOAT, Precision::MEDIUM) .build(); assert(sib.getSize() == PerViewSib::SAMPLER_COUNT); diff --git a/shaders/src/light_directional.fs b/shaders/src/light_directional.fs index 1aaa13cb03..43ac19ddd2 100644 --- a/shaders/src/light_directional.fs +++ b/shaders/src/light_directional.fs @@ -38,7 +38,7 @@ void evaluateDirectionalLight(const MaterialInputs material, float visibility = 1.0; #if defined(HAS_SHADOWING) if (light.NoL > 0.0) { - visibility = shadow(light_shadowMap, getLightSpacePosition()); + visibility = shadow(light_shadowMap, 0u, getLightSpacePosition()); #if defined(MATERIAL_HAS_AMBIENT_OCCLUSION) visibility *= computeMicroShadowing(light.NoL, material.ambientOcclusion); #endif diff --git a/shaders/src/shading_unlit.fs b/shaders/src/shading_unlit.fs index a0c5a2b276..5fa6b7b43b 100644 --- a/shaders/src/shading_unlit.fs +++ b/shaders/src/shading_unlit.fs @@ -36,7 +36,7 @@ vec4 evaluateMaterial(const MaterialInputs material) { #if defined(HAS_DIRECTIONAL_LIGHTING) #if defined(HAS_SHADOWING) - color *= 1.0 - shadow(light_shadowMap, getLightSpacePosition()); + color *= 1.0 - shadow(light_shadowMap, 0u, getLightSpacePosition()); #else color = vec4(0.0); #endif diff --git a/shaders/src/shadowing.fs b/shaders/src/shadowing.fs index d3908f5fc3..c6958339a3 100644 --- a/shaders/src/shadowing.fs +++ b/shaders/src/shadowing.fs @@ -64,7 +64,7 @@ float samplingBias(float depth, const vec2 rpdb, const vec2 texelSize) { return depth; } -float sampleDepth(const lowp sampler2DShadow map, vec2 base, vec2 dudv, float depth, vec2 rpdb) { +float sampleDepth(const lowp sampler2DArrayShadow map, const uint layer, vec2 base, vec2 dudv, float depth, vec2 rpdb) { #if SHADOW_RECEIVER_PLANE_DEPTH_BIAS == SHADOW_RECEIVER_PLANE_DEPTH_BIAS_ENABLED #if SHADOW_SAMPLING_METHOD >= SHADOW_RECEIVER_PLANE_DEPTH_BIAS_MIN_SAMPLING_METHOD depth += dot(dudv, rpdb); @@ -73,19 +73,19 @@ float sampleDepth(const lowp sampler2DShadow map, vec2 base, vec2 dudv, float de // depth must be clamped to support floating-point depth formats. This is to avoid comparing a // value from the depth texture (which is never greater than 1.0) with a greater-than-one // comparison value (which is possible with floating-point formats). - return texture(map, vec3(base + dudv, clamp(depth, 0.0, 1.0))); + return texture(map, vec4(base + dudv, layer, clamp(depth, 0.0, 1.0))); } #if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD -float ShadowSample_Hard(const lowp sampler2DShadow map, const vec2 size, const vec3 position) { +float ShadowSample_Hard(const lowp sampler2DArrayShadow map, const uint layer, const vec2 size, const vec3 position) { vec2 rpdb = computeReceiverPlaneDepthBias(position); float depth = samplingBias(position.z, rpdb, vec2(1.0) / size); - return texture(map, vec3(position.xy, clamp(depth, 0.0, 1.0))); + return texture(map, vec4(position.xy, layer, clamp(depth, 0.0, 1.0))); } #endif #if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW -float ShadowSample_PCF_Low(const lowp sampler2DShadow map, const vec2 size, vec3 position) { +float ShadowSample_PCF_Low(const lowp sampler2DArrayShadow map, const uint layer, const vec2 size, vec3 position) { // Castaño, 2013, "Shadow Mapping Summary Part 1" vec2 texelSize = vec2(1.0) / size; @@ -111,18 +111,18 @@ float ShadowSample_PCF_Low(const lowp sampler2DShadow map, const vec2 size, vec3 float depth = samplingBias(position.z, rpdb, texelSize); float sum = 0.0; - sum += uw.x * vw.x * sampleDepth(map, base, vec2(u.x, v.x), depth, rpdb); - sum += uw.y * vw.x * sampleDepth(map, base, vec2(u.y, v.x), depth, rpdb); + sum += uw.x * vw.x * sampleDepth(map, layer, base, vec2(u.x, v.x), depth, rpdb); + sum += uw.y * vw.x * sampleDepth(map, layer, base, vec2(u.y, v.x), depth, rpdb); - sum += uw.x * vw.y * sampleDepth(map, base, vec2(u.x, v.y), depth, rpdb); - sum += uw.y * vw.y * sampleDepth(map, base, vec2(u.y, v.y), depth, rpdb); + sum += uw.x * vw.y * sampleDepth(map, layer, base, vec2(u.x, v.y), depth, rpdb); + sum += uw.y * vw.y * sampleDepth(map, layer, base, vec2(u.y, v.y), depth, rpdb); return sum * (1.0 / 16.0); } #endif #if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_MEDIUM -float ShadowSample_PCF_Medium(const lowp sampler2DShadow map, const vec2 size, vec3 position) { +float ShadowSample_PCF_Medium(const lowp sampler2DArrayShadow map, const uint layer, const vec2 size, vec3 position) { // Castaño, 2013, "Shadow Mapping Summary Part 1" vec2 texelSize = vec2(1.0) / size; @@ -148,24 +148,24 @@ float ShadowSample_PCF_Medium(const lowp sampler2DShadow map, const vec2 size, v float depth = samplingBias(position.z, rpdb, texelSize); float sum = 0.0; - sum += uw.x * vw.x * sampleDepth(map, base, vec2(u.x, v.x), depth, rpdb); - sum += uw.y * vw.x * sampleDepth(map, base, vec2(u.y, v.x), depth, rpdb); - sum += uw.z * vw.x * sampleDepth(map, base, vec2(u.z, v.x), depth, rpdb); + sum += uw.x * vw.x * sampleDepth(map, layer, base, vec2(u.x, v.x), depth, rpdb); + sum += uw.y * vw.x * sampleDepth(map, layer, base, vec2(u.y, v.x), depth, rpdb); + sum += uw.z * vw.x * sampleDepth(map, layer, base, vec2(u.z, v.x), depth, rpdb); - sum += uw.x * vw.y * sampleDepth(map, base, vec2(u.x, v.y), depth, rpdb); - sum += uw.y * vw.y * sampleDepth(map, base, vec2(u.y, v.y), depth, rpdb); - sum += uw.z * vw.y * sampleDepth(map, base, vec2(u.z, v.y), depth, rpdb); + sum += uw.x * vw.y * sampleDepth(map, layer, base, vec2(u.x, v.y), depth, rpdb); + sum += uw.y * vw.y * sampleDepth(map, layer, base, vec2(u.y, v.y), depth, rpdb); + sum += uw.z * vw.y * sampleDepth(map, layer, base, vec2(u.z, v.y), depth, rpdb); - sum += uw.x * vw.z * sampleDepth(map, base, vec2(u.x, v.z), depth, rpdb); - sum += uw.y * vw.z * sampleDepth(map, base, vec2(u.y, v.z), depth, rpdb); - sum += uw.z * vw.z * sampleDepth(map, base, vec2(u.z, v.z), depth, rpdb); + sum += uw.x * vw.z * sampleDepth(map, layer, base, vec2(u.x, v.z), depth, rpdb); + sum += uw.y * vw.z * sampleDepth(map, layer, base, vec2(u.y, v.z), depth, rpdb); + sum += uw.z * vw.z * sampleDepth(map, layer, base, vec2(u.z, v.z), depth, rpdb); return sum * (1.0 / 144.0); } #endif #if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HIGH -float ShadowSample_PCF_High(const lowp sampler2DShadow map, const vec2 size, vec3 position) { +float ShadowSample_PCF_High(const lowp sampler2DArrayShadow map, const uint layer, const vec2 size, vec3 position) { // Castaño, 2013, "Shadow Mapping Summary Part 1" vec2 texelSize = vec2(1.0) / size; @@ -207,25 +207,25 @@ float ShadowSample_PCF_High(const lowp sampler2DShadow map, const vec2 size, vec float depth = samplingBias(position.z, rpdb, texelSize); float sum = 0.0; - sum += uw.x * vw.x * sampleDepth(map, base, vec2(u.x, v.x), depth, rpdb); - sum += uw.y * vw.x * sampleDepth(map, base, vec2(u.y, v.x), depth, rpdb); - sum += uw.z * vw.x * sampleDepth(map, base, vec2(u.z, v.x), depth, rpdb); - sum += uw.w * vw.x * sampleDepth(map, base, vec2(u.w, v.x), depth, rpdb); + sum += uw.x * vw.x * sampleDepth(map, layer, base, vec2(u.x, v.x), depth, rpdb); + sum += uw.y * vw.x * sampleDepth(map, layer, base, vec2(u.y, v.x), depth, rpdb); + sum += uw.z * vw.x * sampleDepth(map, layer, base, vec2(u.z, v.x), depth, rpdb); + sum += uw.w * vw.x * sampleDepth(map, layer, base, vec2(u.w, v.x), depth, rpdb); - sum += uw.x * vw.y * sampleDepth(map, base, vec2(u.x, v.y), depth, rpdb); - sum += uw.y * vw.y * sampleDepth(map, base, vec2(u.y, v.y), depth, rpdb); - sum += uw.z * vw.y * sampleDepth(map, base, vec2(u.z, v.y), depth, rpdb); - sum += uw.w * vw.y * sampleDepth(map, base, vec2(u.w, v.y), depth, rpdb); + sum += uw.x * vw.y * sampleDepth(map, layer, base, vec2(u.x, v.y), depth, rpdb); + sum += uw.y * vw.y * sampleDepth(map, layer, base, vec2(u.y, v.y), depth, rpdb); + sum += uw.z * vw.y * sampleDepth(map, layer, base, vec2(u.z, v.y), depth, rpdb); + sum += uw.w * vw.y * sampleDepth(map, layer, base, vec2(u.w, v.y), depth, rpdb); - sum += uw.x * vw.z * sampleDepth(map, base, vec2(u.x, v.z), depth, rpdb); - sum += uw.y * vw.z * sampleDepth(map, base, vec2(u.y, v.z), depth, rpdb); - sum += uw.z * vw.z * sampleDepth(map, base, vec2(u.z, v.z), depth, rpdb); - sum += uw.w * vw.z * sampleDepth(map, base, vec2(u.w, v.z), depth, rpdb); + sum += uw.x * vw.z * sampleDepth(map, layer, base, vec2(u.x, v.z), depth, rpdb); + sum += uw.y * vw.z * sampleDepth(map, layer, base, vec2(u.y, v.z), depth, rpdb); + sum += uw.z * vw.z * sampleDepth(map, layer, base, vec2(u.z, v.z), depth, rpdb); + sum += uw.w * vw.z * sampleDepth(map, layer, base, vec2(u.w, v.z), depth, rpdb); - sum += uw.x * vw.w * sampleDepth(map, base, vec2(u.x, v.w), depth, rpdb); - sum += uw.y * vw.w * sampleDepth(map, base, vec2(u.y, v.w), depth, rpdb); - sum += uw.z * vw.w * sampleDepth(map, base, vec2(u.z, v.w), depth, rpdb); - sum += uw.w * vw.w * sampleDepth(map, base, vec2(u.w, v.w), depth, rpdb); + sum += uw.x * vw.w * sampleDepth(map, layer, base, vec2(u.x, v.w), depth, rpdb); + sum += uw.y * vw.w * sampleDepth(map, layer, base, vec2(u.y, v.w), depth, rpdb); + sum += uw.z * vw.w * sampleDepth(map, layer, base, vec2(u.z, v.w), depth, rpdb); + sum += uw.w * vw.w * sampleDepth(map, layer, base, vec2(u.w, v.w), depth, rpdb); return sum * (1.0 / 2704.0); } @@ -240,15 +240,15 @@ float ShadowSample_PCF_High(const lowp sampler2DShadow map, const vec2 size, vec * space. The output is a filtered visibility factor that can be used to multiply * the light intensity. */ -float shadow(const lowp sampler2DShadow shadowMap, const vec3 shadowPosition) { +float shadow(const lowp sampler2DArrayShadow shadowMap, const uint layer, const vec3 shadowPosition) { vec2 size = vec2(textureSize(shadowMap, 0)); #if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD - return ShadowSample_Hard(shadowMap, size, shadowPosition); + return ShadowSample_Hard(shadowMap, layer, size, shadowPosition); #elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW - return ShadowSample_PCF_Low(shadowMap, size, shadowPosition); + return ShadowSample_PCF_Low(shadowMap, layer, size, shadowPosition); #elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_MEDIUM - return ShadowSample_PCF_Medium(shadowMap, size, shadowPosition); + return ShadowSample_PCF_Medium(shadowMap, layer, size, shadowPosition); #elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HIGH - return ShadowSample_PCF_High(shadowMap, size, shadowPosition); + return ShadowSample_PCF_High(shadowMap, layer, size, shadowPosition); #endif }