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/LODGroupManager.cpp | 462 +++++++++++++++++++++++++++++++++++++ 1 file changed, 462 insertions(+) create mode 100644 Runtime/Camera/LODGroupManager.cpp (limited to 'Runtime/Camera/LODGroupManager.cpp') diff --git a/Runtime/Camera/LODGroupManager.cpp b/Runtime/Camera/LODGroupManager.cpp new file mode 100644 index 0000000..0463cf3 --- /dev/null +++ b/Runtime/Camera/LODGroupManager.cpp @@ -0,0 +1,462 @@ +#include "UnityPrefix.h" +#include "LODGroupManager.h" +#include "LODGroup.h" +#include "CullingParameters.h" +#include "Runtime/Profiler/Profiler.h" +#include "Runtime/Utilities/BitUtility.h" +#include "Runtime/Camera/RenderLoops/BuiltinShaderParamUtility.h" +#include "Runtime/Misc/BuildSettings.h" + +PROFILER_INFORMATION (gComputeLOD, "LOD.ComputeLOD", kProfilerRender) + +LODGroupManager* gLODGroupManager = NULL; + +LODGroupManager& GetLODGroupManager () +{ + Assert(gLODGroupManager != NULL); + return *gLODGroupManager; +} + +LODGroupManager* GetLODGroupManagerPtr () +{ + return gLODGroupManager; +} +void CleanupLODGroupManager () +{ + Assert(gLODGroupManager != NULL); + UNITY_DELETE (gLODGroupManager, kMemRenderer); +} + +void InitializeLODGroupManager () +{ + Assert(gLODGroupManager == NULL); + gLODGroupManager = UNITY_NEW_AS_ROOT(LODGroupManager(), kMemRenderer, "LODGroupManager", ""); +} + + +LODGroupManager::LODGroupManager () +{ + m_LODBias = 1.0F; + m_MaximumLOD = 0; + + memset(&m_SelectionData.push_back(), 0, sizeof(LODSelectionData)); +} + +// The basic LOD distance check in orthomode: +// * Pixel size check: if (array[i].pixelHeight < lodGroup.m_Size * 0.5F / parameters.orthoSize * parameters.cameraPixelHeight) +// * Relative height check: if (array[i].relativeHeight < lodGroup.m_Size * 0.5F / parameters.orthoSize) + +// The basic LOD distance check in perspective: +// ... + +// All LOD calculations are distance based "reference point in LOD group" to camera position. +// - Rotating a camera never switches LOD +// - Point based means it's very predictable behaviour that is easy to visualize accurately +// - Fast to calculate +// float distance = CalculateFOVDistanceFudge () * CaclulateLODDistance(); + + +float CalculateFOVHalfAngle (const CullingParameters& parameters) +{ + return tan(Deg2Rad (parameters.lodFieldOfView) * 0.5F); +} + +enum { kScreenRelativeMetric = 0, kPixelMetric = 1, kMetricCount = 2 }; + +void CalculateLODFudge (const CullingParameters& parameters, float* fudge) +{ + float screenRelativeMetric; + if (parameters.isOrthographic) + { + screenRelativeMetric = 2.0F * parameters.orthoSize; + } + else + { + // Half angle at 90 degrees is 1.0 (So we skip halfAngle / 1.0 calculation) + float halfAngle = CalculateFOVHalfAngle(parameters); + screenRelativeMetric = 2.0 * halfAngle; + } + + fudge[kScreenRelativeMetric] = screenRelativeMetric; + fudge[kPixelMetric] = screenRelativeMetric / parameters.cameraPixelHeight; +} + +float CalculateLODDistance (float relativeScreenHeight, float size) +{ + return size / relativeScreenHeight; +} + +float DistanceToRelativeHeight (const CullingParameters& parameters, float distance, float size) +{ + if (parameters.isOrthographic) + { + return size * 0.5F / parameters.orthoSize; + } + else + { + float halfAngle = CalculateFOVHalfAngle(parameters); + return size * 0.5F / (distance * halfAngle); + } +} + + +void LODGroupManager::CalculatePerspectiveLODMask (const LODSelectionData& selection, const Vector3f& position, int maximumLOD, int currentMask, const float* fieldOfViewFudge, UInt8* output, float* fade) +{ + if (selection.forceLODLevelMask != 0) + { + *output = selection.forceLODLevelMask; + *fade = 1.0F; + return; + } + + Vector3f offset = selection.worldReferencePoint - position; + + float sqrDistance = SqrMagnitude(offset); + sqrDistance *= fieldOfViewFudge[kScreenRelativeMetric] * fieldOfViewFudge[kScreenRelativeMetric]; + + // Early out if the object is getting culled because it is too far away. + *output = 0; + *fade = 0.0F; + + // Must use the same metric for everything.... Otherwise this will fail + if (sqrDistance > selection.maxDistanceSqr) + return; + + int maxDistancesCount = selection.maxDistancesCount; + const float* distances = selection.maxDistances; + + bool supportsFade = selection.fadeDistance != 0.0F; + + for (int i=maximumLOD;i 0); + outMasks[0] = 0; + outFades[0] = 0; + int baseMask = 1 << m_MaximumLOD; + if (parameters.isOrthographic) + { + for (int i=1;i> 1; + v |= v >> 2; + v |= v >> 4; + v++; + + UInt32 table[] = { v >> 2, v >> 1 }; + return table[extra]; +} + +// The shader isn't using clamp on the z value of the 3D dither texture. +// Thus we have to ensure that it never actually becomes 1.0 +inline float ClampForGPURepeat (float fade) +{ + return clamp(fade, 0.0F, LOD_FADE_DISABLED); +} + +float LODGroupManager::CalculateLODFade (UInt32 lodGroupIndex, UInt32 rendererActiveLODMask, const UInt8* lodMasks, const float* lodFades) +{ + if (rendererActiveLODMask == 0) + return LOD_FADE_DISABLED; + + // rendererActiveLODMask: + // The mask of all LOD levels that this renderer participates in. + + // The mask of all active LOD levels for this group. + // Eg. LOD 0 and LOD1 enabled -> 1 | 2 + UInt8 activeMaskOfLODGroup = lodMasks[lodGroupIndex]; + + // If renderer is part of all active LOD groups, then it should be completely visible. + if ((rendererActiveLODMask & activeMaskOfLODGroup) == activeMaskOfLODGroup) + return LOD_FADE_DISABLED; + + // If the renderer is part of the lowest bit then it is part of the highest LOD (duh!) + bool isPartOfHighLOD = LowestBit2Consecutive8Bit (activeMaskOfLODGroup) & rendererActiveLODMask; + + // The highest LOD Level uses the computed fade value + if (isPartOfHighLOD) + { + return ClampForGPURepeat(lodFades[lodGroupIndex]); + } + // The lower lod level uses the inverse + else + { + return ClampForGPURepeat(1.0F - lodFades[lodGroupIndex]); + } +} + +void LODGroupManager::ClearAllForceLODMask () +{ + for (int i=0;iGetRenderStats (stats); + + information.triangleCount += stats.triangleCount; + information.vertexCount += stats.vertexCount; + information.rendererCount += 1; + information.submeshCount += stats.submeshCount; + } + } +} + +LODVisualizationInformation LODGroupManager::CalculateVisualizationData (const CullingParameters& cullingParameters, LODGroup& lodGroup, int lodLevel) +{ + LODVisualizationInformation information; + memset(&information, 0, sizeof(information)); + information.activeLODLevel = kInvalidLODGroup; + + // Calculate switch distance + float fudge[kMetricCount]; + CalculateLODFudge (cullingParameters, fudge); + for (int i=0;i 0.00001F && !group.m_LODs.empty(); + if (useLODFade) + { + float baseRelativeHeight = group.m_LODs.front().screenRelativeHeight; + data.fadeDistance = CalculateLODDistance (baseRelativeHeight - group.m_ScreenRelativeTransitionHeight, worldSpaceSize) - CalculateLODDistance (baseRelativeHeight, worldSpaceSize); + } + else + data.fadeDistance = 0.0F; +} + +void LODGroupManager::RemoveLODGroup (LODGroup& group) +{ + // Remove from array by replacing with the last element. + Assert(group.m_CachedRenderers.empty()); + + int index = group.m_LODGroup; + Assert(index != 0); + + // Update LODGroup index of the LODGroup we moved from the back + m_SelectionData.back().lodGroup->NotifyLODGroupManagerIndexChange(index); + + m_SelectionData[index] = m_SelectionData.back(); + m_SelectionData.pop_back(); + + group.m_LODGroup = kInvalidLODGroup; +} + + +#if ENABLE_UNIT_TESTS + +#include "External/UnitTest++/src/UnitTest++.h" + +SUITE (LODGroupManagerTests) +{ +TEST (LODGroupManagerTests_PrevPowerOfTwoUInt8) +{ + for (int i=0;i<7;i++) + { + CHECK_EQUAL (1 << i, LowestBit2Consecutive8Bit(1 << i)); + CHECK_EQUAL (1 << i, LowestBit2Consecutive8Bit((1 << i) | (1 << (i+1)))); + } +} +} + +#endif -- cgit v1.1-26-g67d0