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.
216 lines
7.2 KiB
C++
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
|