bmh/FlightSimulation/Plugins/CesiumForUnreal_5.4/Source/CesiumRuntime/Private/CesiumViewExtension.cpp
2025-02-07 22:52:32 +08:00

209 lines
7.2 KiB
C++

// Copyright 2020-2024 CesiumGS, Inc. and Contributors
#include "CesiumViewExtension.h"
#include "Cesium3DTileset.h"
#include "CesiumCommon.h"
#include "Runtime/Launch/Resources/Version.h"
using namespace Cesium3DTilesSelection;
CesiumViewExtension::CesiumViewExtension(const FAutoRegister& autoRegister)
: FSceneViewExtensionBase(autoRegister) {}
CesiumViewExtension::~CesiumViewExtension() = default;
TileOcclusionState CesiumViewExtension::getPrimitiveOcclusionState(
const FPrimitiveComponentId& id,
bool previouslyOccluded,
float frameTimeCutoff) const {
if (_currentOcclusionResults.occlusionResultsByView.size() == 0) {
return TileOcclusionState::OcclusionUnavailable;
}
bool isOccluded = false;
bool historyMissing = false;
for (const SceneViewOcclusionResults& viewOcclusionResults :
_currentOcclusionResults.occlusionResultsByView) {
const PrimitiveOcclusionResult* pOcclusionResult =
viewOcclusionResults.PrimitiveOcclusionResults.Find(id);
if (pOcclusionResult &&
pOcclusionResult->LastConsideredTime >= frameTimeCutoff) {
if (!pOcclusionResult->OcclusionStateWasDefiniteLastFrame) {
return TileOcclusionState::OcclusionUnavailable;
}
if (previouslyOccluded) {
if (pOcclusionResult->LastPixelsPercentage > 0.01f) {
return TileOcclusionState::NotOccluded;
}
} else if (!pOcclusionResult->WasOccludedLastFrame) {
return TileOcclusionState::NotOccluded;
}
isOccluded = true;
} else {
historyMissing = true;
}
}
if (historyMissing) {
return TileOcclusionState::OcclusionUnavailable;
} else if (isOccluded) {
return TileOcclusionState::Occluded;
} else {
return TileOcclusionState::NotOccluded;
}
}
void CesiumViewExtension::SetupViewFamily(FSceneViewFamily& InViewFamily) {}
void CesiumViewExtension::SetupView(
FSceneViewFamily& InViewFamily,
FSceneView& InView) {}
void CesiumViewExtension::BeginRenderViewFamily(
FSceneViewFamily& InViewFamily) {
if (!this->_isEnabled)
return;
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::DequeueOcclusionResults)
if (!_occlusionResultsQueue.IsEmpty()) {
// Recycle the current occlusion results.
for (SceneViewOcclusionResults& occlusionResults :
_currentOcclusionResults.occlusionResultsByView) {
occlusionResults.PrimitiveOcclusionResults.Reset();
_recycledOcclusionResultSets.Enqueue(
std::move(occlusionResults.PrimitiveOcclusionResults));
}
_currentOcclusionResults = {};
// Update occlusion results from the queue.
_currentOcclusionResults = std::move(*_occlusionResultsQueue.Peek());
_occlusionResultsQueue.Pop();
}
}
namespace {
const TSet<FPrimitiveOcclusionHistory, FPrimitiveOcclusionHistoryKeyFuncs>&
getOcclusionHistorySet(const FSceneViewState* pViewState) {
return pViewState->Occlusion.PrimitiveOcclusionHistorySet;
}
} // namespace
void CesiumViewExtension::PostRenderViewFamily_RenderThread(
FRDGBuilder& GraphBuilder,
FSceneViewFamily& InViewFamily) {
if (!this->_isEnabled)
return;
if (_frameNumber_renderThread != InViewFamily.FrameNumber) {
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::EnqueueAggregatedOcclusion)
if (_frameNumber_renderThread != -1) {
_occlusionResultsQueue.Enqueue(
std::move(_currentAggregation_renderThread));
_currentAggregation_renderThread = {};
}
_frameNumber_renderThread = InViewFamily.FrameNumber;
}
TRACE_CPUPROFILER_EVENT_SCOPE(Cesium::AggregateOcclusionForViewFamily)
for (const FSceneView* pView : InViewFamily.Views) {
if (pView == nullptr || pView->State == nullptr)
continue;
const FSceneViewState* pViewState = pView->State->GetConcreteViewState();
if (pViewState && getOcclusionHistorySet(pViewState).Num()) {
SceneViewOcclusionResults& occlusionResults =
_currentAggregation_renderThread.occlusionResultsByView
.emplace_back();
// Do we actually need the view?
occlusionResults.pView = pView;
if (!_recycledOcclusionResultSets.IsEmpty()) {
// Recycle a previously allocated occlusion history set, if one is
// available.
occlusionResults.PrimitiveOcclusionResults =
std::move(*_recycledOcclusionResultSets.Peek());
_recycledOcclusionResultSets.Pop();
} else {
// If no previously-allocated set exists, just allocate a new one. It
// will be recycled later.
}
occlusionResults.PrimitiveOcclusionResults.Reserve(
getOcclusionHistorySet(pViewState).Num());
for (const auto& element : getOcclusionHistorySet(pViewState)) {
occlusionResults.PrimitiveOcclusionResults.Emplace(element);
}
// Unreal will not execute occlusion queries that get frustum culled in a
// particular view, leaving the occlusion results indefinite. And by just
// looking at the PrimitiveOcclusionHistorySet, we can't distinguish
// occlusion queries that haven't completed "yet" from occlusion queries
// that were culled. So here we detect primitives that have been
// conclusively proven to be not visible (outside the view frustum) and
// also mark them definitely occluded.
FScene* pScene = InViewFamily.Scene->GetRenderScene();
if (pView->bIsViewInfo && pScene != nullptr) {
const FViewInfo* pViewInfo = static_cast<const FViewInfo*>(pView);
const FSceneBitArray& visibility = pViewInfo->PrimitiveVisibilityMap;
auto& occlusion = occlusionResults.PrimitiveOcclusionResults;
const uint32 PrimitiveCount = pScene->Primitives.Num();
for (uint32 i = 0; i < PrimitiveCount; ++i) {
FPrimitiveSceneInfo* pSceneInfo = pScene->Primitives[i];
if (pSceneInfo == nullptr)
continue;
bool setOcclusionState = false;
bool isOccluded = false;
// Unreal will never compute occlusion for primitives that are
// selected in the Editor. So treat these as unoccluded.
#if WITH_EDITOR
if (GIsEditor) {
if (pScene->PrimitivesSelected[i]) {
setOcclusionState = true;
isOccluded = false;
}
}
#endif
// If this primitive is not visible at all (and also not selected!),
// treat is as occluded.
if (!setOcclusionState && !visibility[i]) {
setOcclusionState = true;
isOccluded = true;
}
if (setOcclusionState) {
const PrimitiveOcclusionResult* pOcclusionResult =
occlusion.Find(pSceneInfo->PrimitiveComponentId);
if (!pOcclusionResult || pOcclusionResult->LastConsideredTime <
pViewState->LastRenderTime) {
// No valid occlusion history for this culled primitive, so create
// it.
occlusion.Emplace(PrimitiveOcclusionResult(
pSceneInfo->PrimitiveComponentId,
pViewState->LastRenderTime,
isOccluded ? 0.0f : 100.0f,
true,
isOccluded));
}
}
}
}
}
}
}
void CesiumViewExtension::SetEnabled(bool enabled) {
this->_isEnabled = enabled;
}