// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using UnityEngine;
namespace UltimateXR.Extensions.Unity.Render
{
///
/// extensions.
/// Most functionality has been copied from:
/// https://github.com/JulienHeijmans/EditorScripts/blob/master/Scripts/Utility/Editor/LODExtendedUtility.cs, which
/// in turn copied functionality from:
/// https://github.com/Unity-Technologies/AutoLOD/blob/master/Scripts/Extensions/LODGroupExtensions.cs
///
public static class LODGroupExt
{
#region Public Methods
///
/// Gets the LOD level index that should be enabled from a specific view.
///
/// Component to check
/// Camera to use as point of view
/// LOD level index that should be enabled
public static int GetVisibleLevel(this LODGroup lodGroup, Camera camera)
{
if (camera == null)
{
return lodGroup.lodCount - 1;
}
var lods = lodGroup.GetLODs();
var relativeHeight = GetRelativeHeight(lodGroup, camera);
int lodIndex = lodGroup.lodCount - 1;
for (int i = 0; i < lods.Length; i++)
{
var lod = lods[i];
if (relativeHeight >= lod.screenRelativeTransitionHeight)
{
lodIndex = i;
break;
}
}
return lodIndex;
}
///
/// Manually enables all renderers belonging to a LOD level.
///
/// Component to process
/// Level whose renderers to enable
public static void EnableLevelRenderers(this LODGroup lodGroup, int level)
{
var lods = lodGroup.GetLODs();
for (int i = 0; i < lods.Length; i++)
{
foreach (Renderer renderer in lods[i].renderers)
{
if (renderer != null)
{
renderer.enabled = i == level;
}
}
}
}
///
/// Manually enables the renderers from all LOD levels.
///
/// Component to process
public static void EnableAllLevelRenderers(this LODGroup lodGroup)
{
var lods = lodGroup.GetLODs();
for (int i = 0; i < lods.Length; i++)
{
foreach (Renderer renderer in lods[i].renderers)
{
if (renderer != null)
{
renderer.enabled = true;
}
}
}
}
#endregion
#region Private Methods
///
/// Computes the relative height in the camera view.
///
/// Component to check
/// Camera to use as point of view
/// Relative height
private static float GetRelativeHeight(LODGroup lodGroup, Camera camera)
{
var distance = (lodGroup.transform.TransformPoint(lodGroup.localReferencePoint) - camera.transform.position).magnitude;
return DistanceToRelativeHeight(camera, distance / QualitySettings.lodBias, GetWorldSpaceSize(lodGroup));
}
///
/// Computes the relative height in the camera view.
///
/// Camera to use as point of view
/// Distance to the camera
/// Largest axis in world-space
/// Relative height
private static float DistanceToRelativeHeight(Camera camera, float distance, float size)
{
if (camera.orthographic)
{
return size * 0.5F / camera.orthographicSize;
}
var halfAngle = Mathf.Tan(Mathf.Deg2Rad * camera.fieldOfView * 0.5F);
var relativeHeight = size * 0.5F / (distance * halfAngle);
return relativeHeight;
}
///
/// Computes the largest axis of the in world-space.
///
/// Component to process
/// World space size
private static float GetWorldSpaceSize(LODGroup lodGroup)
{
return GetWorldSpaceScale(lodGroup.transform) * lodGroup.size;
}
///
/// Computes the largest scale axis.
///
/// Transform to get the largest scale of
/// Largest scale axis
private static float GetWorldSpaceScale(Transform transform)
{
var scale = transform.lossyScale;
float largestAxis = Mathf.Abs(scale.x);
largestAxis = Mathf.Max(largestAxis, Mathf.Abs(scale.y));
largestAxis = Mathf.Max(largestAxis, Mathf.Abs(scale.z));
return largestAxis;
}
#endregion
}
}