Files
filament/filament/src/ShadowMapManager.h
T
Mathias Agopian cd903b412f move some private headers out of src/details
src/details now only has the private headers of public types/classes.
Private/implementation classes have their header next to them under src.

This makes things more consistant.
2021-08-16 16:50:35 -07:00

216 lines
7.2 KiB
C++

/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_DETAILS_SHADOWMAPMANAGER_H
#define TNT_FILAMENT_DETAILS_SHADOWMAPMANAGER_H
#include <filament/Viewport.h>
#include "ShadowMap.h"
#include "TypedUniformBuffer.h"
#include "details/Engine.h"
#include "details/Scene.h"
#include <private/filament/EngineEnums.h>
#include <private/backend/DriverApi.h>
#include <private/backend/DriverApiForward.h>
#include <private/backend/SamplerGroup.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <utils/FixedCapacityVector.h>
#include <math/vec3.h>
#include <array>
#include <memory>
#include <vector>
namespace filament {
class FView;
class FrameGraph;
class ShadowMap;
class RenderPass;
struct ShadowMappingUniforms {
std::array<math::mat4f, CONFIG_MAX_SHADOW_CASCADES> lightFromWorldMatrix;
math::float4 cascadeSplits;
math::float3 shadowBias;
float ssContactShadowDistance;
uint32_t directionalShadows;
uint32_t cascades;
};
class ShadowMapManager {
public:
using ShadowMappingUniforms = ShadowMappingUniforms;
enum class ShadowTechnique : uint8_t {
NONE = 0x0u,
SHADOW_MAP = 0x1u,
SCREEN_SPACE = 0x2u,
};
explicit ShadowMapManager(FEngine& engine);
~ShadowMapManager();
// Reset shadow map layout.
void reset() noexcept;
void setShadowCascades(size_t lightIndex, LightManager::ShadowOptions const* options) noexcept;
void addSpotShadowMap(size_t lightIndex, LightManager::ShadowOptions const* options) noexcept;
// Updates all of the shadow maps and performs culling.
// Returns true if any of the shadow maps have visible shadows.
ShadowTechnique update(FEngine& engine, FView& view,
TypedUniformBuffer<ShadowUib>& shadowUb,
FScene::RenderableSoa& renderableData, FScene::LightSoa& lightData) noexcept;
// valid after calling update() above
ShadowMappingUniforms getShadowMappingUniforms() const noexcept {
return mShadowMappingUniforms;
}
// Renders all of the shadow maps.
void render(FrameGraph& fg, FEngine& engine, backend::DriverApi& driver,
RenderPass const& pass, FView& view) noexcept;
const ShadowMap* getCascadeShadowMap(size_t cascade) const noexcept {
assert_invariant(cascade < CONFIG_MAX_SHADOW_CASCADES);
auto shadowMap = std::launder(reinterpret_cast<ShadowMap const*>(&mShadowMapCache[cascade]));
return shadowMap;
}
private:
struct TextureRequirements {
uint16_t size = 0;
uint8_t layers = 0;
uint8_t levels = 0;
} mTextureRequirements;
ShadowTechnique updateCascadeShadowMaps(FEngine& engine, FView& view,
FScene::RenderableSoa& renderableData, FScene::LightSoa& lightData) noexcept;
ShadowTechnique updateSpotShadowMaps(FEngine& engine, FView& view,
TypedUniformBuffer<ShadowUib>& shadowUb,
FScene::RenderableSoa& renderableData, FScene::LightSoa& lightData) noexcept;
void calculateTextureRequirements(FEngine& engine, FView& view, FScene::LightSoa& lightData) noexcept;
class ShadowMapEntry {
public:
ShadowMapEntry() = default;
ShadowMapEntry(ShadowMap* shadowMap, size_t light,
LightManager::ShadowOptions const* options) :
mShadowMap(shadowMap), mOptions(options), mLightIndex(light) {
}
explicit operator bool() const { return mShadowMap != nullptr; }
void setLayer(uint8_t layer) noexcept { mLayer = layer; }
uint8_t getLayer() const noexcept { return mLayer; }
LightManager::ShadowOptions const* getShadowOptions() const noexcept { return mOptions; }
ShadowMap& getShadowMap() const { return *mShadowMap; }
size_t getLightIndex() const { return mLightIndex; }
bool hasVisibleShadows() const { return mShadowMap->hasVisibleShadows(); }
private:
ShadowMap* mShadowMap = nullptr;
LightManager::ShadowOptions const* mOptions = nullptr;
uint32_t mLightIndex = 0;
uint8_t mLayer = 0;
};
class CascadeSplits {
public:
constexpr static size_t SPLIT_COUNT = CONFIG_MAX_SHADOW_CASCADES + 1;
struct Params {
math::mat4f proj;
float near = 0.0f;
float far = 0.0f;
size_t cascadeCount = 1;
std::array<float, SPLIT_COUNT> splitPositions = { 0.0f };
bool operator!=(const Params& rhs) const {
return proj != rhs.proj ||
near != rhs.near ||
far != rhs.far ||
cascadeCount != rhs.cascadeCount ||
splitPositions != rhs.splitPositions;
}
};
CascadeSplits() noexcept : CascadeSplits(Params{}) {}
explicit CascadeSplits(Params const& params) noexcept;
// Split positions in world-space.
const float* beginWs() const { return mSplitsWs; }
const float* endWs() const { return mSplitsWs + mSplitCount; }
// Split positions in clip-space.
const float* beginCs() const { return mSplitsCs; }
const float* endCs() const { return mSplitsCs + mSplitCount; }
private:
float mSplitsWs[SPLIT_COUNT];
float mSplitsCs[SPLIT_COUNT];
size_t mSplitCount;
};
CascadeSplits::Params mCascadeSplitParams;
CascadeSplits mCascadeSplits;
// 16-bits seems enough.
// TODO: make it an option.
// TODO: iOS does not support the DEPTH16 texture format.
backend::TextureFormat mTextureFormat = backend::TextureFormat::DEPTH16;
float mTextureZResolution = 1.0f / (1u << 16u);
ShadowMappingUniforms mShadowMappingUniforms;
utils::FixedCapacityVector<ShadowMapEntry> mCascadeShadowMaps{
utils::FixedCapacityVector<ShadowMapEntry>::with_capacity(
CONFIG_MAX_SHADOW_CASCADES) };
utils::FixedCapacityVector<ShadowMapEntry> mSpotShadowMaps{
utils::FixedCapacityVector<ShadowMapEntry>::with_capacity(
CONFIG_MAX_SHADOW_CASTING_SPOTS) };
// 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.
// Each ShadowMap is currently 128 bytes.
using ShadowMapStorage = std::aligned_storage<sizeof(ShadowMap), alignof(ShadowMap)>::type;
std::array<ShadowMapStorage,
CONFIG_MAX_SHADOW_CASCADES + CONFIG_MAX_SHADOW_CASTING_SPOTS> mShadowMapCache;
};
} // namespace filament
template<> struct utils::EnableBitMaskOperators<filament::ShadowMapManager::ShadowTechnique>
: public std::true_type {};
#endif //TNT_FILAMENT_DETAILS_SHADOWMAPMANAGER_H