Compare commits

...

15 Commits

Author SHA1 Message Date
Benjamin Doherty
18dab53920 All changes 2022-11-14 22:20:59 -08:00
Benjamin Doherty
b754b81e6f Almost all the changes 2022-11-14 22:16:58 -08:00
Benjamin Doherty
65bb66f90c Even more shader changes 2022-11-14 22:00:10 -08:00
Benjamin Doherty
a0af84d034 Some more shader changes 2022-11-14 21:56:50 -08:00
Benjamin Doherty
3cdaf3feeb ShadowMapManager.h changes 2022-11-14 17:18:00 -08:00
Benjamin Doherty
da7d1b6fa9 Update Scene.cpp 2022-11-14 17:09:55 -08:00
Benjamin Doherty
3129226839 Fix literal 0 2022-11-14 17:07:55 -08:00
Benjamin Doherty
6935acafff Changes to ShadowMapManager 2022-11-14 17:07:25 -08:00
Benjamin Doherty
d8103f4fd6 Update ShaderGenerator.cpp 2022-11-14 16:55:50 -08:00
Benjamin Doherty
09a13f4015 Some shadowing changes 2022-11-14 15:25:08 -08:00
Benjamin Doherty
e888023102 Some shader changes 2022-11-14 15:00:09 -08:00
Benjamin Doherty
f62f4736f0 Adjust LightsUib 2022-11-14 13:39:08 -08:00
Benjamin Doherty
a378272d56 Remove some more uniforms 2022-11-14 13:34:26 -08:00
Benjamin Doherty
3d61938fcf Remove lightFromWorldMatrix from PerViewUniforms 2022-11-14 13:30:54 -08:00
Benjamin Doherty
a9f3937da6 Trivial changes 2022-11-14 13:05:52 -08:00
19 changed files with 98 additions and 90 deletions

View File

@@ -9,6 +9,7 @@ A new header is inserted each time a *tag* is created.
- gltfio: recompute bounding boxes with morph targets - gltfio: recompute bounding boxes with morph targets
- engine: add missing getters on `MaterialInstance` - engine: add missing getters on `MaterialInstance`
- WebGL: add missing `ColorGrading` JS bindings - WebGL: add missing `ColorGrading` JS bindings
- engine: improvements/cleanup of Shadow mapping code [⚠️ **Recompile Materials**]
## v1.28.3 ## v1.28.3

View File

@@ -290,14 +290,10 @@ void PerViewUniforms::prepareShadowMapping(bool highPrecision) noexcept {
void PerViewUniforms::prepareShadowSampling(PerViewUib& uniforms, void PerViewUniforms::prepareShadowSampling(PerViewUib& uniforms,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept { ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
uniforms.lightFromWorldMatrix = shadowMappingUniforms.lightFromWorldMatrix;
uniforms.cascadeSplits = shadowMappingUniforms.cascadeSplits; uniforms.cascadeSplits = shadowMappingUniforms.cascadeSplits;
uniforms.shadowBulbRadiusLs = shadowMappingUniforms.shadowBulbRadiusLs;
uniforms.shadowBias = shadowMappingUniforms.shadowBias;
uniforms.ssContactShadowDistance = shadowMappingUniforms.ssContactShadowDistance; uniforms.ssContactShadowDistance = shadowMappingUniforms.ssContactShadowDistance;
uniforms.directionalShadows = shadowMappingUniforms.directionalShadows; uniforms.directionalShadows = shadowMappingUniforms.directionalShadows;
uniforms.cascades = shadowMappingUniforms.cascades; uniforms.cascades = shadowMappingUniforms.cascades;
uniforms.cascades |= uint32_t(shadowMappingUniforms.elvsm) << 31u;
} }
void PerViewUniforms::prepareShadowVSM(Handle<HwTexture> texture, void PerViewUniforms::prepareShadowVSM(Handle<HwTexture> texture,

View File

@@ -97,8 +97,10 @@ void ShadowMapManager::setDirectionalShadowMap(size_t lightIndex,
LightManager::ShadowOptions const* options) noexcept { LightManager::ShadowOptions const* options) noexcept {
assert_invariant(options->shadowCascades <= CONFIG_MAX_SHADOW_CASCADES); assert_invariant(options->shadowCascades <= CONFIG_MAX_SHADOW_CASCADES);
for (size_t c = 0; c < options->shadowCascades; c++) { for (size_t c = 0; c < options->shadowCascades; c++) {
auto* pShadowMap = getCascadeShadowMap(c); const size_t i = c;
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, c, 0, options); assert_invariant(i < CONFIG_MAX_SHADOW_CASCADES);
auto* pShadowMap = getCascadeShadowMap(i);
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, i, 0, options);
mCascadeShadowMaps.push_back(pShadowMap); mCascadeShadowMaps.push_back(pShadowMap);
} }
} }
@@ -107,17 +109,19 @@ void ShadowMapManager::addShadowMap(size_t lightIndex, bool spotlight,
LightManager::ShadowOptions const* options) noexcept { LightManager::ShadowOptions const* options) noexcept {
if (spotlight) { if (spotlight) {
const size_t c = mSpotShadowMaps.size(); const size_t c = mSpotShadowMaps.size();
assert_invariant(c < CONFIG_MAX_SHADOWMAPS); const size_t i = c + CONFIG_MAX_SHADOW_CASCADES;
auto* pShadowMap = getPointOrSpotShadowMap(c); assert_invariant(i < CONFIG_MAX_SHADOWMAPS);
pShadowMap->initialize(lightIndex, ShadowType::SPOT, c, 0, options); auto* pShadowMap = getPointOrSpotShadowMap(i);
pShadowMap->initialize(lightIndex, ShadowType::SPOT, i, 0, options);
mSpotShadowMaps.push_back(pShadowMap); mSpotShadowMaps.push_back(pShadowMap);
} else { } else {
// point-light, generate 6 independent shadowmaps // point-light, generate 6 independent shadowmaps
for (size_t face = 0; face < 6; face++) { for (size_t face = 0; face < 6; face++) {
const size_t c = mSpotShadowMaps.size(); const size_t c = mSpotShadowMaps.size();
assert_invariant(c < CONFIG_MAX_SHADOWMAPS); const size_t i = c + CONFIG_MAX_SHADOW_CASCADES;
auto* pShadowMap = getPointOrSpotShadowMap(c); assert_invariant(i < CONFIG_MAX_SHADOWMAPS);
pShadowMap->initialize(lightIndex, ShadowType::POINT, c, face, options); auto* pShadowMap = getPointOrSpotShadowMap(i);
pShadowMap->initialize(lightIndex, ShadowType::POINT, i, face, options);
mSpotShadowMaps.push_back(pShadowMap); mSpotShadowMaps.push_back(pShadowMap);
} }
} }
@@ -455,7 +459,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
// entire camera frustum, as if we only had a single cascade. // entire camera frustum, as if we only had a single cascade.
ShadowMap& shadowMap = *mCascadeShadowMaps[0]; ShadowMap& shadowMap = *mCascadeShadowMaps[0];
auto shaderParameters = shadowMap.updateDirectional(mEngine, shadowMap.updateDirectional(mEngine,
lightData, 0, cameraInfo, shadowMapInfo, *scene, sceneInfo); lightData, 0, cameraInfo, shadowMapInfo, *scene, sceneInfo);
hasVisibleShadows = shadowMap.hasVisibleShadows(); hasVisibleShadows = shadowMap.hasVisibleShadows();
@@ -464,18 +468,6 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
Frustum const& frustum = shadowMap.getCamera().getCullingFrustum(); Frustum const& frustum = shadowMap.getCamera().getCullingFrustum();
FView::cullRenderables(engine.getJobSystem(), renderableData, frustum, FView::cullRenderables(engine.getJobSystem(), renderableData, frustum,
VISIBLE_DIR_SHADOW_RENDERABLE_BIT); VISIBLE_DIR_SHADOW_RENDERABLE_BIT);
// Set shadowBias, using the first directional cascade.
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
// note: normalBias is set to zero for VSM
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
// Texel size is constant for directional light (although that's not true when LISPSM
// is used, but in that case we're pretending it is).
const float wsTexelSize = shaderParameters.texelSizeAtOneMeterWs;
mShadowMappingUniforms.shadowBias = normalBias * wsTexelSize;
mShadowMappingUniforms.shadowBulbRadiusLs =
mSoftShadowOptions.penumbraScale * options.shadowBulbRadius / wsTexelSize;
mShadowMappingUniforms.elvsm = options.vsm.elvsm;
} }
} }
@@ -528,6 +520,10 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
mShadowMappingUniforms.cascadeSplits = wsSplitPositionUniform; mShadowMappingUniforms.cascadeSplits = wsSplitPositionUniform;
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
// note: normalBias is set to zero for VSM
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
for (size_t i = 0, c = mCascadeShadowMaps.size(); i < c; i++) { for (size_t i = 0, c = mCascadeShadowMaps.size(); i < c; i++) {
assert_invariant(mCascadeShadowMaps[i]); assert_invariant(mCascadeShadowMaps[i]);
@@ -541,7 +537,22 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
lightData, 0, cameraInfo, shadowMapInfo, *scene, sceneInfo); lightData, 0, cameraInfo, shadowMapInfo, *scene, sceneInfo);
if (shadowMap.hasVisibleShadows()) { if (shadowMap.hasVisibleShadows()) {
mShadowMappingUniforms.lightFromWorldMatrix[i] = shaderParameters.lightSpace; const size_t shadowIndex = shadowMap.getShadowIndex();
assert_invariant(shadowIndex == i);
// Texel size is constant for directional light (although that's not true when LISPSM
// is used, but in that case we're pretending it is).
const float wsTexelSize = shaderParameters.texelSizeAtOneMeterWs;
auto& s = mShadowUb.edit();
s.shadows[shadowIndex].layer = shadowMap.getLayer();
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSize;
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSize;
s.shadows[shadowIndex].elvsm = options.vsm.elvsm;
s.shadows[shadowIndex].bulbRadiusLs =
mSoftShadowOptions.penumbraScale * options.shadowBulbRadius / wsTexelSize;
shadowTechnique |= ShadowTechnique::SHADOW_MAP; shadowTechnique |= ShadowTechnique::SHADOW_MAP;
cascadeHasVisibleShadows |= 0x1u << i; cascadeHasVisibleShadows |= 0x1u << i;
} }
@@ -669,6 +680,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
auto& s = mShadowUb.edit(); auto& s = mShadowUb.edit();
const double n = shadowMap.getCamera().getNear(); const double n = shadowMap.getCamera().getNear();
const double f = shadowMap.getCamera().getCullingFar(); const double f = shadowMap.getCamera().getCullingFar();
s.shadows[shadowIndex].layer = shadowMap.getLayer();
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace; s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
s.shadows[shadowIndex].direction = direction; s.shadows[shadowIndex].direction = direction;
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter; s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
@@ -679,6 +691,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
s.shadows[shadowIndex].bulbRadiusLs = s.shadows[shadowIndex].bulbRadiusLs =
mSoftShadowOptions.penumbraScale * options->shadowBulbRadius mSoftShadowOptions.penumbraScale * options->shadowBulbRadius
/ wsTexelSizeAtOneMeter; / wsTexelSizeAtOneMeter;
} }
} }
@@ -740,7 +753,6 @@ void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap,
// and if we need to generate it, update all the UBO data // and if we need to generate it, update all the UBO data
// Note: this below is done for all six faces even if it sets identical values each time
if (shadowMap.hasVisibleShadows()) { if (shadowMap.hasVisibleShadows()) {
const size_t shadowIndex = shadowMap.getShadowIndex(); const size_t shadowIndex = shadowMap.getShadowIndex();
const float wsTexelSizeAtOneMeter = shaderParameters.texelSizeAtOneMeterWs; const float wsTexelSizeAtOneMeter = shaderParameters.texelSizeAtOneMeterWs;
@@ -750,7 +762,7 @@ void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap,
auto& s = mShadowUb.edit(); auto& s = mShadowUb.edit();
const double n = shadowMap.getCamera().getNear(); const double n = shadowMap.getCamera().getNear();
const double f = shadowMap.getCamera().getCullingFar(); const double f = shadowMap.getCamera().getCullingFar();
s.shadows[shadowIndex].layer = shadowMap.getLayer();
s.shadows[shadowIndex].lightFromWorldMatrix = {}; // no texture matrix for point lights s.shadows[shadowIndex].lightFromWorldMatrix = {}; // no texture matrix for point lights
s.shadows[shadowIndex].direction = {}; // no direction of point lights s.shadows[shadowIndex].direction = {}; // no direction of point lights
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter; s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
@@ -779,14 +791,12 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine
shadowTechnique |= ShadowTechnique::SHADOW_MAP; shadowTechnique |= ShadowTechnique::SHADOW_MAP;
for (auto const* pShadowMap : mSpotShadowMaps) { for (auto const* pShadowMap : mSpotShadowMaps) {
const size_t lightIndex = pShadowMap->getLightIndex(); const size_t lightIndex = pShadowMap->getLightIndex();
// gather the per-light (not per shadow map) information. For point lights we will
// FIXME: currently we have one slot per shadowmap in the UBO, but we now have up to // "see" 6 shadowmaps (one per face), we must use the first face one, the shader
// 6 shadowmap per light. So for now, we only write the data of the face 0, // knows how to find the entry for other faces (they're guaranteed to be sequential).
// and the shader will figure out where to find the other face (layer+face)
if (pShadowMap->getFace() == 0) { if (pShadowMap->getFace() == 0) {
shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly? shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly?
shadowInfo[lightIndex].index = pShadowMap->getShadowIndex(); shadowInfo[lightIndex].index = pShadowMap->getShadowIndex();
shadowInfo[lightIndex].layer = pShadowMap->getLayer();
} }
} }
} }

View File

@@ -45,14 +45,10 @@ class FrameGraph;
class RenderPass; class RenderPass;
struct ShadowMappingUniforms { struct ShadowMappingUniforms {
std::array<math::mat4f, CONFIG_MAX_SHADOW_CASCADES> lightFromWorldMatrix;
math::float4 cascadeSplits; math::float4 cascadeSplits;
float shadowBulbRadiusLs;
float shadowBias;
float ssContactShadowDistance; float ssContactShadowDistance;
uint32_t directionalShadows; uint32_t directionalShadows;
uint32_t cascades; uint32_t cascades;
bool elvsm;
}; };
class ShadowMapManager { class ShadowMapManager {
@@ -105,7 +101,7 @@ public:
ShadowMap* getPointOrSpotShadowMap(size_t index) noexcept { ShadowMap* getPointOrSpotShadowMap(size_t index) noexcept {
assert_invariant(index < CONFIG_MAX_SHADOWMAPS); assert_invariant(index < CONFIG_MAX_SHADOWMAPS);
return std::launder(reinterpret_cast<ShadowMap*>( return std::launder(reinterpret_cast<ShadowMap*>(
&mShadowMapCache[CONFIG_MAX_SHADOW_CASCADES + index])); &mShadowMapCache[index]));
} }
ShadowMap const* getPointOrSpotShadowMap(size_t spot) const noexcept { ShadowMap const* getPointOrSpotShadowMap(size_t spot) const noexcept {
@@ -215,13 +211,13 @@ private:
utils::FixedCapacityVector<ShadowMap*> mSpotShadowMaps{ utils::FixedCapacityVector<ShadowMap*> mSpotShadowMaps{
utils::FixedCapacityVector<ShadowMap*>::with_capacity( utils::FixedCapacityVector<ShadowMap*>::with_capacity(
CONFIG_MAX_SHADOWMAPS) }; CONFIG_MAX_SHADOWMAPS - CONFIG_MAX_SHADOW_CASCADES) };
// inline storage for all our ShadowMap objects, we can't easily use a std::array<> directly. // inline storage for all our ShadowMap objects, we can't easily use a std::array<> directly.
// because ShadowMap doesn't have a default ctor, and we avoid out-of-line allocations. // because ShadowMap doesn't have a default ctor, and we avoid out-of-line allocations.
// Each ShadowMap is currently 40 bytes (total of 2.5KB for 64 shadow maps) // Each ShadowMap is currently 40 bytes (total of 2.5KB for 64 shadow maps)
using ShadowMapStorage = std::aligned_storage<sizeof(ShadowMap), alignof(ShadowMap)>::type; using ShadowMapStorage = std::aligned_storage<sizeof(ShadowMap), alignof(ShadowMap)>::type;
std::array<ShadowMapStorage, CONFIG_MAX_SHADOW_CASCADES + CONFIG_MAX_SHADOWMAPS> mShadowMapCache; std::array<ShadowMapStorage, CONFIG_MAX_SHADOWMAPS> mShadowMapCache;
}; };
} // namespace filament } // namespace filament

View File

@@ -343,9 +343,10 @@ void FScene::prepareDynamicLights(const CameraInfo& camera, ArenaScope& rootAren
lp[gpuIndex].typeShadow = LightsUib::packTypeShadow( lp[gpuIndex].typeShadow = LightsUib::packTypeShadow(
lcm.isPointLight(li) ? 0u : 1u, lcm.isPointLight(li) ? 0u : 1u,
shadowInfo[i].contactShadows, shadowInfo[i].contactShadows,
shadowInfo[i].index, shadowInfo[i].index);
shadowInfo[i].layer); lp[gpuIndex].channels = LightsUib::packChannels(
lp[gpuIndex].channels = LightsUib::packChannels(lcm.getLightChannels(li), shadowInfo[i].castsShadows); lcm.getLightChannels(li),
shadowInfo[i].castsShadows);
} }
driver.updateBufferObject(lightUbh, { lp, positionalLightCount * sizeof(LightsUib) }, 0); driver.updateBufferObject(lightUbh, { lp, positionalLightCount * sizeof(LightsUib) }, 0);

View File

@@ -155,7 +155,6 @@ public:
bool castsShadows = false; // whether this light casts shadows bool castsShadows = false; // whether this light casts shadows
bool contactShadows = false; // whether this light casts contact shadows bool contactShadows = false; // whether this light casts contact shadows
uint8_t index = 0; // an index into the arrays in the Shadows uniform buffer uint8_t index = 0; // an index into the arrays in the Shadows uniform buffer
uint8_t layer = 0; // which layer of the shadow texture array to sample from
}; };
enum { enum {
@@ -179,7 +178,8 @@ public:
LightSoa const& getLightData() const noexcept { return mLightData; } LightSoa const& getLightData() const noexcept { return mLightData; }
LightSoa& getLightData() noexcept { return mLightData; } LightSoa& getLightData() noexcept { return mLightData; }
void updateUBOs(utils::Range<uint32_t> visibleRenderables, backend::Handle<backend::HwBufferObject> renderableUbh) noexcept; void updateUBOs(utils::Range<uint32_t> visibleRenderables,
backend::Handle<backend::HwBufferObject> renderableUbh) noexcept;
bool hasContactShadows() const noexcept; bool hasContactShadows() const noexcept;

View File

@@ -27,7 +27,7 @@
namespace filament { namespace filament {
// update this when a new version of filament wouldn't work with older materials // update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 28; static constexpr size_t MATERIAL_VERSION = 29;
/** /**
* Supported shading models * Supported shading models

View File

@@ -124,12 +124,10 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
// bit 0-3: cascade count // bit 0-3: cascade count
// bit 4: visualize cascades // bit 4: visualize cascades
// bit 8-11: cascade has visible shadows // bit 8-11: cascade has visible shadows
// bit 31: elvsm
uint32_t cascades; uint32_t cascades;
float shadowBulbRadiusLs; // light radius in light-space float reserved0;
float shadowBias; // normal bias float reserved1; // normal bias
float shadowPenumbraRatioScale; // For DPCF or PCSS, scale penumbra ratio for artistic use float shadowPenumbraRatioScale; // For DPCF or PCSS, scale penumbra ratio for artistic use
std::array<math::mat4f, CONFIG_MAX_SHADOW_CASCADES> lightFromWorldMatrix;
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
// VSM shadows [variant: VSM] // VSM shadows [variant: VSM]
@@ -164,7 +162,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
float ssrStride; // ssr texel stride, >= 1.0 float ssrStride; // ssr texel stride, >= 1.0
// bring PerViewUib to 2 KiB // bring PerViewUib to 2 KiB
math::float4 reserved[47]; math::float4 reserved[63];
}; };
// 2 KiB == 128 float4s // 2 KiB == 128 float4s
@@ -229,11 +227,11 @@ struct LightsUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
math::float2 spotScaleOffset; // { scale, offset } math::float2 spotScaleOffset; // { scale, offset }
float reserved3; // 0 float reserved3; // 0
float intensity; // float float intensity; // float
uint32_t typeShadow; // 0x00.ll.ii.ct (t: 0=point, 1=spot, c:contact, ii: index, ll: layer) uint32_t typeShadow; // 0x00.00.ii.ct (t: 0=point, 1=spot, c:contact, ii: index)
uint32_t channels; // 0x000c00ll (ll: light channels, c: caster) uint32_t channels; // 0x000c00ll (ll: light channels, c: caster)
static uint32_t packTypeShadow(uint8_t type, bool contactShadow, uint8_t index, uint8_t layer) noexcept { static uint32_t packTypeShadow(uint8_t type, bool contactShadow, uint8_t index) noexcept {
return (type & 0xF) | (contactShadow ? 0x10 : 0x00) | (index << 8) | (layer << 16); return (type & 0xF) | (contactShadow ? 0x10 : 0x00) | (index << 8);
} }
static uint32_t packChannels(uint8_t lightChannels, bool castShadows) noexcept { static uint32_t packChannels(uint8_t lightChannels, bool castShadows) noexcept {
return lightChannels | (castShadows ? 0x10000 : 0); return lightChannels | (castShadows ? 0x10000 : 0);
@@ -258,6 +256,11 @@ struct ShadowUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
float bulbRadiusLs; // 4 float bulbRadiusLs; // 4
float nearOverFarMinusNear; // 4 float nearOverFarMinusNear; // 4
bool elvsm; // 4 bool elvsm; // 4
uint32_t layer; // 4
uint32_t reserved0; // 4
uint32_t reserved1; // 4
uint32_t reserved2; // 4
}; };
ShadowData shadows[CONFIG_MAX_SHADOWMAPS]; ShadowData shadows[CONFIG_MAX_SHADOWMAPS];
}; };

View File

@@ -105,10 +105,9 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
{ "cascadeSplits", 0, Type::FLOAT4, Precision::HIGH }, { "cascadeSplits", 0, Type::FLOAT4, Precision::HIGH },
{ "cascades", 0, Type::UINT }, { "cascades", 0, Type::UINT },
{ "shadowBulbRadiusLs", 0, Type::FLOAT }, { "reserved0", 0, Type::FLOAT },
{ "shadowBias", 0, Type::FLOAT }, { "reserved1", 0, Type::FLOAT },
{ "shadowPenumbraRatioScale", 0, Type::FLOAT }, { "shadowPenumbraRatioScale", 0, Type::FLOAT },
{ "lightFromWorldMatrix", 4, Type::MAT4, Precision::HIGH },
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// VSM shadows [variant: VSM] // VSM shadows [variant: VSM]

View File

@@ -287,6 +287,10 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib()); UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib());
cg.generateUniforms(vs, ShaderStage::VERTEX, cg.generateUniforms(vs, ShaderStage::VERTEX,
UniformBindingPoints::PER_RENDERABLE, UibGenerator::getPerRenderableUib()); UniformBindingPoints::PER_RENDERABLE, UibGenerator::getPerRenderableUib());
if (litVariants && filament::Variant::isShadowReceiverVariant(variant)) {
cg.generateUniforms(vs, ShaderStage::FRAGMENT,
UniformBindingPoints::SHADOW, UibGenerator::getShadowUib());
}
if (variant.hasSkinningOrMorphing()) { if (variant.hasSkinningOrMorphing()) {
cg.generateUniforms(vs, ShaderStage::VERTEX, cg.generateUniforms(vs, ShaderStage::VERTEX,
UniformBindingPoints::PER_RENDERABLE_BONES, UniformBindingPoints::PER_RENDERABLE_BONES,

View File

@@ -9,7 +9,6 @@ struct Light {
bool contactShadows; bool contactShadows;
uint type; uint type;
uint shadowIndex; uint shadowIndex;
uint shadowLayer;
uint channels; uint channels;
}; };

View File

@@ -9,6 +9,10 @@ struct ShadowData {
float bulbRadiusLs; float bulbRadiusLs;
float nearOverFarMinusNear; float nearOverFarMinusNear;
bool elvsm; bool elvsm;
uint layer;
uint reserved0;
uint reserved1;
uint reserved2;
}; };
struct BoneData { struct BoneData {

View File

@@ -134,8 +134,9 @@ highp vec4 getCascadeLightSpacePosition(uint cascade) {
} }
return computeLightSpacePosition(getWorldPosition(), getWorldNormalVector(), return computeLightSpacePosition(getWorldPosition(), getWorldNormalVector(),
frameUniforms.lightDirection, frameUniforms.shadowBias, frameUniforms.lightDirection,
frameUniforms.lightFromWorldMatrix[cascade]); shadowUniforms.shadows[cascade].normalBias,
shadowUniforms.shadows[cascade].lightFromWorldMatrix);
} }
#endif #endif

View File

@@ -13,10 +13,6 @@ int getInstanceIndex() {
// Uniforms access // Uniforms access
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
mat4 getLightFromWorldMatrix() {
return frameUniforms.lightFromWorldMatrix[0];
}
PerRenderableData getObjectUniforms() { PerRenderableData getObjectUniforms() {
#if defined(MATERIAL_HAS_INSTANCES) #if defined(MATERIAL_HAS_INSTANCES)
// the material manages instancing, all instances share the same uniform block. // the material manages instancing, all instances share the same uniform block.

View File

@@ -56,9 +56,8 @@ void evaluateDirectionalLight(const MaterialInputs material,
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u)); bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u));
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u); bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
if (hasDirectionalShadows && cascadeHasVisibleShadows) { if (hasDirectionalShadows && cascadeHasVisibleShadows) {
uint layer = cascade;
highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f); highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f);
visibility = shadow(true, light_shadowMap, layer, 0u, shadowPosition, 0.0f); visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
} }
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) { if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) { if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {

View File

@@ -158,7 +158,6 @@ Light getLight(const uint lightIndex) {
light.type = (typeShadow & 0x1u); light.type = (typeShadow & 0x1u);
#if defined(VARIANT_HAS_SHADOWING) #if defined(VARIANT_HAS_SHADOWING)
light.shadowIndex = (typeShadow >> 8u) & 0xFFu; light.shadowIndex = (typeShadow >> 8u) & 0xFFu;
light.shadowLayer = (typeShadow >> 16u) & 0xFFu;
light.castsShadows = bool(channels & 0x10000u); light.castsShadows = bool(channels & 0x10000u);
if (light.type == LIGHT_TYPE_SPOT) { if (light.type == LIGHT_TYPE_SPOT) {
light.zLight = dot(shadowUniforms.shadows[light.shadowIndex].lightFromWorldZ, vec4(worldPosition, 1.0)); light.zLight = dot(shadowUniforms.shadows[light.shadowIndex].lightFromWorldZ, vec4(worldPosition, 1.0));
@@ -211,19 +210,20 @@ void evaluatePunctualLights(const MaterialInputs material,
#if defined(VARIANT_HAS_SHADOWING) #if defined(VARIANT_HAS_SHADOWING)
if (light.NoL > 0.0) { if (light.NoL > 0.0) {
if (light.castsShadows) { if (light.castsShadows) {
uint layer = light.shadowLayer; uint shadowIndex = light.shadowIndex;
highp vec4 shadowPosition; highp vec4 shadowPosition;
if (light.type == LIGHT_TYPE_POINT) { if (light.type == LIGHT_TYPE_POINT) {
// point-light shadows are sampled from a direction // point-light shadows are sampled from a direction
highp vec3 r = getWorldPosition() - light.worldPosition; highp vec3 r = getWorldPosition() - light.worldPosition;
highp vec4 nf = shadowUniforms.shadows[light.shadowIndex].lightFromWorldZ; highp uint face = 0u;
// getShadowPosition returns zLight which is needed for PCSS/DPCF // getShadowPosition returns zLight which is needed for PCSS/DPCF
shadowPosition = getShadowPosition(r, nf, layer, light.zLight); shadowPosition = getShadowPosition(r, shadowIndex, light.zLight, face);
shadowIndex += face;
} else { } else {
// getShadowPosition needs zLight for applying the normal bias // getShadowPosition needs zLight for applying the normal bias
shadowPosition = getShadowPosition(false, light.shadowIndex, 0u, light.zLight); shadowPosition = getShadowPosition(false, shadowIndex, 0u, light.zLight);
} }
visibility = shadow(false, light_shadowMap, layer, light.shadowIndex, visibility = shadow(false, light_shadowMap, shadowIndex,
shadowPosition, light.zLight); shadowPosition, light.zLight);
} }
if (light.contactShadows && visibility > 0.0) { if (light.contactShadows && visibility > 0.0) {

View File

@@ -143,7 +143,9 @@ void main() {
#if defined(VARIANT_HAS_SHADOWING) && defined(VARIANT_HAS_DIRECTIONAL_LIGHTING) #if defined(VARIANT_HAS_SHADOWING) && defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
vertex_lightSpacePosition = computeLightSpacePosition( vertex_lightSpacePosition = computeLightSpacePosition(
vertex_worldPosition.xyz, vertex_worldNormal, vertex_worldPosition.xyz, vertex_worldNormal,
frameUniforms.lightDirection, frameUniforms.shadowBias, getLightFromWorldMatrix()); frameUniforms.lightDirection,
shadowUniforms.shadows[0].normalBias,
shadowUniforms.shadows[0].lightFromWorldMatrix);
#endif #endif
#endif // !defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER) #endif // !defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER)

View File

@@ -50,9 +50,8 @@ vec4 evaluateMaterial(const MaterialInputs material) {
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u)); bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u));
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u); bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
if (hasDirectionalShadows && cascadeHasVisibleShadows) { if (hasDirectionalShadows && cascadeHasVisibleShadows) {
uint layer = cascade;
highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f); highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f);
visibility = shadow(true, light_shadowMap, layer, 0u, shadowPosition, 0.0f); visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
} }
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) { if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) { if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {

View File

@@ -161,7 +161,7 @@ float getPenumbraLs(const bool DIRECTIONAL, const uint index, const highp float
float penumbra; float penumbra;
// This conditional is resolved at compile time // This conditional is resolved at compile time
if (DIRECTIONAL) { if (DIRECTIONAL) {
penumbra = frameUniforms.shadowBulbRadiusLs; penumbra = shadowUniforms.shadows[index].bulbRadiusLs;
} else { } else {
// the penumbra radius depends on the light-space z for spotlights // the penumbra radius depends on the light-space z for spotlights
penumbra = shadowUniforms.shadows[index].bulbRadiusLs / zLight; penumbra = shadowUniforms.shadows[index].bulbRadiusLs / zLight;
@@ -495,8 +495,8 @@ highp vec4 getShadowPosition(const bool DIRECTIONAL,
} }
// get {texture coordinate, layer} for point shadow maps // get {texture coordinate, layer} for point shadow maps
highp vec4 getShadowPosition(const highp vec3 r, const highp vec4 nf, highp vec4 getShadowPosition(const highp vec3 r, const highp uint shadowIndex,
inout uint layer, out highp float d) { out highp float d, out highp uint face) {
highp vec4 tc; highp vec4 tc;
highp float rx = abs(r.x); highp float rx = abs(r.x);
highp float ry = abs(r.y); highp float ry = abs(r.y);
@@ -506,20 +506,22 @@ highp vec4 getShadowPosition(const highp vec3 r, const highp vec4 nf,
if (d == rx) { if (d == rx) {
tc.x = r.x >= 0.0 ? r.z : -r.z; tc.x = r.x >= 0.0 ? r.z : -r.z;
tc.y = r.y; tc.y = r.y;
layer += (r.x >= 0.0 ? 0u : 1u); face = (r.x >= 0.0 ? 0u : 1u);
} else if (d == ry) { } else if (d == ry) {
tc.x = r.y >= 0.0 ? r.x : -r.x; tc.x = r.y >= 0.0 ? r.x : -r.x;
tc.y = r.z; tc.y = r.z;
layer += (r.y >= 0.0 ? 2u : 3u); face = (r.y >= 0.0 ? 2u : 3u);
} else { } else {
tc.x = r.z >= 0.0 ? -r.x : r.x; tc.x = r.z >= 0.0 ? -r.x : r.x;
tc.y = r.y; tc.y = r.y;
layer += (r.z >= 0.0 ? 4u : 5u); face = (r.z >= 0.0 ? 4u : 5u);
} }
// ma is guaranteed to be >= sc and tc // ma is guaranteed to be >= sc and tc
tc.xy = (tc.xy * ma + vec2(1.0)) * 0.5; tc.xy = (tc.xy * ma + vec2(1.0)) * 0.5;
highp vec4 nf = shadowUniforms.shadows[shadowIndex + face].lightFromWorldZ;
// z coordinate of the normalized fragment position in light-space // z coordinate of the normalized fragment position in light-space
// i.e.: remap [near, far] to [0,1] : d = (d - n) / (f - n) // i.e.: remap [near, far] to [0,1] : d = (d - n) / (f - n)
d = nf[2] + nf[3] * d; d = nf[2] + nf[3] * d;
@@ -542,7 +544,8 @@ highp vec4 getShadowPosition(const highp vec3 r, const highp vec4 nf,
// PCF sampling // PCF sampling
float shadow(const bool DIRECTIONAL, float shadow(const bool DIRECTIONAL,
const mediump sampler2DArrayShadow shadowMap, const mediump sampler2DArrayShadow shadowMap,
const uint layer, const uint index, highp vec4 shadowPosition, highp float zLight) { const uint index, highp vec4 shadowPosition, highp float zLight) {
uint layer = shadowUniforms.shadows[index].layer;
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD #if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
return ShadowSample_PCF_Hard(shadowMap, layer, shadowPosition); return ShadowSample_PCF_Hard(shadowMap, layer, shadowPosition);
#elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW #elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
@@ -553,16 +556,11 @@ float shadow(const bool DIRECTIONAL,
// Shadow requiring a sampler2D sampler (VSM, DPCF and PCSS) // Shadow requiring a sampler2D sampler (VSM, DPCF and PCSS)
float shadow(const bool DIRECTIONAL, float shadow(const bool DIRECTIONAL,
const mediump sampler2DArray shadowMap, const mediump sampler2DArray shadowMap,
const uint layer, const uint index, highp vec4 shadowPosition, highp float zLight) { const uint index, highp vec4 shadowPosition, highp float zLight) {
uint layer = shadowUniforms.shadows[index].layer;
// This conditional is resolved at compile time // This conditional is resolved at compile time
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_EVSM) { if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_EVSM) {
bool elvsm = false; bool elvsm = shadowUniforms.shadows[index].elvsm;
if (DIRECTIONAL) {
elvsm = bool((frameUniforms.cascades >> 31u) & 1u);
} else {
elvsm = shadowUniforms.shadows[index].elvsm;
}
return ShadowSample_VSM(elvsm, shadowMap, layer, shadowPosition); return ShadowSample_VSM(elvsm, shadowMap, layer, shadowPosition);
} }