From 15740faf9fe9fe4be08965098bbf2947e096aeeb Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 14 Aug 2019 22:50:43 +0800 Subject: +Unity Runtime code --- Runtime/Camera/SceneCulling.cpp | 412 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 Runtime/Camera/SceneCulling.cpp (limited to 'Runtime/Camera/SceneCulling.cpp') diff --git a/Runtime/Camera/SceneCulling.cpp b/Runtime/Camera/SceneCulling.cpp new file mode 100644 index 0000000..ad5e4ed --- /dev/null +++ b/Runtime/Camera/SceneCulling.cpp @@ -0,0 +1,412 @@ +#include "UnityPrefix.h" +#include "SceneCulling.h" +#include "CullingParameters.h" +#include "Runtime/Geometry/Intersection.h" +#include "UmbraBackwardsCompatibility.h" +#include "SceneNode.h" +#include "Runtime/Geometry/AABB.h" + + +using Umbra::OcclusionBuffer; + +static bool IsLayerDistanceCulled (UInt32 layer, const AABB& aabb, const SceneCullingParameters& params); +static void ExtractUmbraCameraTransformFromCullingParameters (const CullingParameters& params, Umbra::CameraTransform& output); +static void CullSceneWithLegacyUmbraDeprecated (SceneCullingParameters& cullingParams, CullingOutput& output, Umbra::Query* q, const Umbra_3_0::Tome* t); + +// Reduce the index list using Scene::IsNodeVisible. +// Takes the index list as input and output, after the function the indices that are not visible will have been removed. +static void ProcessIndexListIsNodeVisible (IndexList& list, const SceneNode* nodes, const AABB* bounds, const SceneCullingParameters& params) +{ + int size = list.size; + // Check layers and cull distances + int visibleCountNodes = 0; + for (int i = 0; i < size; ++i) + { + int index = list.indices[i]; + const SceneNode& node = nodes[index]; + const AABB& aabb = bounds[index]; + if (IsNodeVisible(node, aabb, params)) + list.indices[visibleCountNodes++] = index; + } + + list.size = visibleCountNodes; +} + + +static void CullDynamicObjectsWithoutUmbra (IndexList& visibleObjects, const SceneCullingParameters& cullingParams, const AABB* aabbs, size_t count) +{ + int visibleIndex = 0; + for (int i=0;itestAABBVisibility((Umbra::Vector3&)mn, (Umbra::Vector3&)mx); + + if (result != OcclusionBuffer::OCCLUDED) + visibleObjects[visibleIndex++] = i; + } + + visibleObjects.size = visibleIndex; +} + +void CullSceneWithoutUmbra (const SceneCullingParameters& cullingParams, CullingOutput& output) +{ + for (int i=0;isetDebugRenderer(cullingParams.umbraDebugRenderer); + + // Legacy Umbra queries for PVS Tomes + Assert(tome->getStatistic(Umbra::Tome::STAT_PORTAL_DATA_SIZE) != 0); + e = query->queryPortalVisibility(umbraFlags, *output.umbraVisibility, camera); + + //If camera is out of generated view volumes (case 554981), fall back to view frustum culling + if (e == Umbra::Query::ERROR_OUTSIDE_SCENE) + { + cullingParams.useOcclusionCulling = false; + cullingParams.useShadowCasterCulling = false; + CullSceneWithoutUmbra( cullingParams, output ); + return; + } + + // Process static objects with Unity specific culling (cullingMask / LOD etc) + IndexList& staticObjects = output.visible[kStaticRenderers]; + staticObjects.size = output.umbraVisibility->getOutputObjects()->getSize(); + + ProcessIndexListIsNodeVisible(output.visible[kStaticRenderers], cullingParams.renderers[kStaticRenderers].nodes, cullingParams.renderers[kStaticRenderers].bounds, cullingParams); + output.umbraVisibility->getOutputObjects()->setSize(staticObjects.size); + + // Process dynamic objects + for (int i=kDynamicRenderer;igetOutputBuffer()); + ProcessIndexListIsNodeVisible(output.visible[i], cullingParams.renderers[i].nodes, cullingParams.renderers[i].bounds, cullingParams); + } +} + +static void SplitCombinedDynamicList (Umbra::IndexList& indices, CullingOutput& sceneCullingOutput) +{ + int startIndices[kVisibleListCount]; + startIndices[kStaticRenderers] = -1; + int offset = 0; + for (int t=kDynamicRenderer;t= 0 ;t--) + { + DebugAssert(t != kStaticRenderers); + if (index >= startIndices[t]) + { + IndexList& indices = sceneCullingOutput.visible[t]; + indices[indices.size++] = index - startIndices[t]; + break; + } + } + } +} + +// Unity has multiple dynamic bounding volume arrays. +// Umbra's shadow caster culling needs a single list of all dynamic renderers +static void GenerateCombinedDynamicList (const CullingOutput& sceneCullingOutput, const RendererCullData* renderers, dynamic_array& indexList, dynamic_array& minMaxBounds) +{ + size_t visibleSize = 0; + size_t totalSize = 0; + for (int t=kDynamicRenderer;tumbraVisibility; + + dynamic_array visibleSceneIndexListCombined (kMemTempAlloc); + dynamic_array dynamicBounds (kMemTempAlloc); + + ////@TODO: This extra copying could maybe be removed or moved to not be per light? + GenerateCombinedDynamicList (*cullingParams.sceneVisbilityForShadowCulling, cullingParams.renderers, visibleSceneIndexListCombined, dynamicBounds); + + size_t totalDynamicCount = dynamicBounds.size() / 2; + size_t totalStaticCount = cullingParams.renderers[kStaticRenderers].rendererCount; + + int* dynamicCasterIndices; + ALLOC_TEMP(dynamicCasterIndices, int, totalDynamicCount); + + // The output visible static & dynamic caster index lists + Umbra::IndexList staticCasterList (output.visible[kStaticRenderers].indices, totalStaticCount); + Umbra::IndexList dynamicCasterList(dynamicCasterIndices, totalDynamicCount); + + // The current scene visibility (input for umbra occlusion culling) + const Umbra::IndexList sceneVisibleDynamicIndexList (visibleSceneIndexListCombined.begin(), visibleSceneIndexListCombined.size(), visibleSceneIndexListCombined.size()); + + + query->setDebugRenderer(cullingParams.umbraDebugRenderer); + + // TODO: this can be done right after the visibility query and only needs to be done once + // per camera position + // TODO: store shadowCuller so that it can be shared across threads + Umbra::ShadowCullerExt* shadowCuller; + ALLOC_TEMP(shadowCuller, Umbra::ShadowCullerExt, 1); + new (shadowCuller) Umbra::ShadowCullerExt( + cullingParams.umbraTome.tome, + inputSceneVisibility, + (Umbra::Vector3&)cullingParams.lightDir, + (const Umbra::Vector3*)dynamicBounds.data(), + totalDynamicCount, + &sceneVisibleDynamicIndexList); + + // The last two parameters: jobIdx, numTotalJobs. These can be called from mulitple threads + query->queryStaticShadowCasters (*shadowCuller, staticCasterList, 0, 1); + query->queryDynamicShadowCasters(*shadowCuller, dynamicCasterList, (const Umbra::Vector3*)dynamicBounds.data(), totalDynamicCount); + + output.visible[kStaticRenderers].size = staticCasterList.getSize(); + SplitCombinedDynamicList (dynamicCasterList, output); + + for (int i=0;i Sqr(cullDist)); + } + default: + return false; + } +} + +void ExtractUmbraCameraTransformFromCullingParameters (const CullingParameters& params, Umbra::CameraTransform& output) +{ + if (params.cullingPlaneCount > 6) + output.setUserClipPlanes((Umbra::Vector4*)¶ms.cullingPlanes[6], params.cullingPlaneCount-6); + output.set((Umbra::Matrix4x4&)params.worldToClipMatrix, (Umbra::Vector3&)params.position); +} + +#if SUPPORT_BACKWARDS_COMPATIBLE_UMBRA + +static void CullDynamicObjectsUmbraDeprecated (IndexList& visibleObjects, const AABB* aabbs, size_t count, Umbra_3_0::Region* region) +{ + // TODO dynamic objects with legacy Tomes properly + int visibleIndex = 0; + for (int i=0;iisAABBVisible((Umbra_3_0::Vector3&)mn, (Umbra_3_0::Vector3&)mx); + + if (isVisible) + visibleObjects[visibleIndex++] = i; + } + + visibleObjects.size = visibleIndex; +} + +static void CullDynamicObjectsWithoutUmbraInOut (IndexList& visibleObjects, const SceneCullingParameters& cullingParams, const AABB* aabbs) +{ + int visibleIndex = 0; + for (int i=0;iinit(tome); + + Umbra_3_0::Region* region; + ALLOC_TEMP(region, Umbra_3_0::Region, 1); + region->init(); + query->setVisibilityRegionOutput(region); + + + Umbra_3_0::CameraTransform camera; + if (cullingParams.cullingPlaneCount > 6) + camera.setUserClipPlanes((Umbra_3_0::Vector4*)&cullingParams.cullingPlanes[6], cullingParams.cullingPlaneCount-6); + + camera.set((Umbra_3_0::Matrix4x4&)cullingParams.worldToClipMatrix, (Umbra_3_0::Vector3&)cullingParams.position); + + Umbra_3_0::IndexList staticObjs(output.visible[kStaticRenderers].indices, output.visible[kStaticRenderers].reservedSize); + + Umbra_3_0::Query::ErrorCode e; + + int flags = 0; + if (tome->getStatistic(Umbra_3_0::Tome::STAT_PORTAL_DATA_SIZE)) + flags |= Umbra_3_0::Query::QUERYFLAG_PORTAL; + else // TODO: handle other cases? + flags |= Umbra_3_0::Query::QUERYFLAG_PVS; + + e = query->queryCameraVisibility(flags, &staticObjs, NULL, camera); + //Fallback to view frustum culling if queryCameraVisibility failed + if (e != Umbra_3_0::Query::ERROR_OK) + { + cullingParams.useOcclusionCulling = false; + cullingParams.useShadowCasterCulling = false; + CullSceneWithoutUmbra(cullingParams, output); + return; + } + output.visible[kStaticRenderers].size = staticObjs.getSize(); + + // camera can move outside view volume Assert(e == Umbra::Query::ERROR_OK); + // Extract visible indices + if (!query->supportVFCulling()) + CullDynamicObjectsWithoutUmbraInOut (output.visible[kStaticRenderers], cullingParams, cullingParams.renderers[kStaticRenderers].bounds); + + //output.umbraVisibility->getOutputObjects()->setSize(output.visible[kStaticRenderers].size); + + ProcessIndexListIsNodeVisible(output.visible[kStaticRenderers], cullingParams.renderers[kStaticRenderers].nodes, cullingParams.renderers[kStaticRenderers].bounds, cullingParams); + + for (int i=kDynamicRenderer;i