Search Unity

LODGroup.ForceLOD() with crossfade

Discussion in 'Scripting' started by sewy, Jun 17, 2019.

  1. sewy

    sewy

    Joined:
    Oct 11, 2015
    Posts:
    150
    Hi,

    Is it possible to use LODGroup.ForceLOD(), and somehow keep the CrossFade functionality?

    Due to the fact, we need to switch LODs at exact distance (rather then percents in pixels), I came up with own LOD Distance Switcher, but would like to use the CrossFade as well.
     
  2. sewy

    sewy

    Joined:
    Oct 11, 2015
    Posts:
    150
    I have actualy found solution, that suits my purpose, which actualy does not answers the Q, but in this case can be used.

    I want to switch LODs at exact distance with CrossFade so I am using normal LODGroup functionality with custom calculation of screenRelativeTransitionHeight for given distance.
    For calculating that, I have found code for function GetRelativeHeight() at unity git (new), where I present my exact distance instead of calculating it from camera position, doing so for every LOD in the group.
    LOD bias has to be set to 1.
     
    Last edited: Apr 16, 2021
    Hobodi likes this.
  3. sewy

    sewy

    Joined:
    Oct 11, 2015
    Posts:
    150
    To reply to myself again, this approach stops working when it will calculate similar screenRelativeTransitionHeight for multiple distances - this leads to LODs be shown on shorter distance (or skipped completely).
     
  4. sarahnorthway

    sarahnorthway

    Joined:
    Jul 16, 2015
    Posts:
    78
    This is probably too hacky and/or slow to ship, but I had the same need, so thank you for your suggestion of dynamically setting screenRelativeTransitionHeight. My solution forces the LOD I want active based on a discrete zoom level, while still using Unity's LOD animation system. My code:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Configuration;
    5. using System.Linq;
    6. using UnityEngine;
    7.  
    8. /// <summary>
    9. /// Change the way LODGroups work, so they're based on discrete zoom level not distance from camera.
    10. /// </summary>
    11. [RequireComponent(typeof(LODGroup))]
    12. public class NWLODGroup : MonoBehaviour {
    13.     private static readonly List<NWLODGroup> allGroups = new();
    14.     private LODGroup baseLODGroup;
    15.     private LOD[] originalLODs;
    16.    
    17.     private void Awake() {
    18.         baseLODGroup = GetComponent<LODGroup>();
    19.         allGroups.AddSafe(this);
    20.         originalLODs = baseLODGroup.GetLODs();
    21.     }
    22.  
    23.     private void OnEnable() {
    24.         SetLOD(0.5f);
    25.     }
    26.  
    27.     public static void SetAllLOD(float zoomLevelPercent) {
    28.         foreach (NWLODGroup group in allGroups) {
    29.             group.SetLOD(zoomLevelPercent);
    30.         }
    31.     }
    32.  
    33.     public void SetLOD(float zoomLevelPercent) {
    34.         if (!isActiveAndEnabled) return;
    35.        
    36.         LOD[] lods = baseLODGroup.GetLODs();
    37.         if (originalLODs.Length != lods.Length) {
    38.             Debug.LogError("NWLODGroup with changed LOD list size " + this.GetPath());
    39.             originalLODs = lods;
    40.             return;
    41.         }
    42.         if (lods.Length <= 0) return;
    43.        
    44.         int lodLevel = originalLODs.Length - 1;
    45.         for (int i = 0; i < originalLODs.Length; i++) {
    46.             if (zoomLevelPercent >= originalLODs[i].screenRelativeTransitionHeight) {
    47.                 lodLevel = i;
    48.                 break;
    49.             }
    50.         }
    51.        
    52.         // 0 has the most detail, 2 has the least detail
    53.         // before lodLevel set all LODs to 100% (do not use), at lodLevel and after set to 0% (always use)
    54.         // except they can't be equal, so subtract/add a small value and hope for the best
    55.         for (int i = 0; i < lods.Length; i++) {
    56.             if (i < lodLevel) {
    57.                 lods[i].screenRelativeTransitionHeight = 1.0f - i * 0.0001f;
    58.             } else {
    59.                 lods[i].screenRelativeTransitionHeight = 0.0f + (lods.Length - 1 - i) * 0.0001f;
    60.             }
    61.         }
    62.         baseLODGroup.SetLODs(lods);
    63.     }
    64.  
    65.     private void OnDestroy() {
    66.         allGroups.RemoveSafe(this);
    67.     }
    68. }