J'ai créé ce script pour imposer un changement uniquement en fonction de la distance, avec en tête une vue en 3 isométrique, de sorte que tous les objets de la carte changent de LOD en même temps en fonction du niveau de zoom. Toutefois, le script a été conçu pour fonctionner que la caméra soi en mode conique ou orthogonal. Il est inspiré initialement de ce script-là de Justin Diffenderfer, que j'ai modifié pour l'automatiser et le rendre applicable aux caméras orthogonales.
Il suffit d'attacher ce script à un objet contenant déjà un LOD Group, et le reste est automatique. Comme une taille d'écran ne se traduit pas immédiatement en distance, il a fallu prendre quelques hypothèses pour étalonner le modèle. En l'occurrence, pour la vue conique, la profondeur de champ de la caméra et la distance maximale de visibilité de l'objet (cull) du LOD Group. Pour le mode orthogonal, j'ai considéré arbitrairement qu'une taille de 1 montrait l'objet dans tout l'écran. On peut changer ce comportement en changeant la valeur de niveauQualitéSpécifique, cf. infra.
Les paramètres publics
public Camera cameraActive;
La caméra au regard de laquelle les LOD sont calculés. Initialisé à Camera.main si non renseigné.
Je n'ai pas prévu que la caméra puisse être changée à la volée en cours d'exécution puisque je n'en ai pas besoin dans mon projet, mais ça ne doit pas être très dur à réaliser.
public bool Cutoff = true;
(Inspiré de Justin Diffenderfer) "Vrai" si on veut que les objets soient cachés au delà de la limite de vision indiquée dans le LOD Group d'origine.
public int Skip = 4;
(Inspiré de Justin Diffenderfer) Valeur n indique que le script n'est exécuté qu'une fois toutes les n frames, utile pour économiser des efforts au processeur.
public int niveauQualitéSpécifique = 4;
Niveau de qualité réglable à la main pour chaque objet : un facteur multiplicateur à la distance à laquelle le niveau de détail change. Se comporte comme le facteur "LOD Bias" mais spécifique à l'objet.
Voila, ça a l'air de fonctionner, mais je ne crois pas avoir testé ce script dans toutes les situations possibles, merci de me dire s'il y a des erreurs ou des manques. Voire, de m'indiquer la correction
Code : Tout sélectionner
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LOD_ortho : MonoBehaviour {
List<Renderer[]> LOD_Renderer = new List<Renderer[]>();
List<float> LOD_Distance = new List<float>(); // Distance à laquelle les objets changent de LOD.
List<float> LOD_Ortho = new List<float>(); // Taille orthographique correspondante.
public bool Cutoff = true; // Hide the object if it is beyond the maximum distance.
public int Skip = 4;
public Camera cameraActive;
public int niveauQualitéSpécifique = 4;
protected int _skipIndex = 0;
protected int _currentLOD = 0;
void Start()
{
if (!cameraActive)
{
cameraActive = Camera.main;
}
float profondeurDeChamp = cameraActive.farClipPlane - cameraActive.nearClipPlane;
LODGroup leLODgroup = this.GetComponentInChildren<LODGroup> ();
float Rcull = leLODgroup.GetLODs () [leLODgroup.lodCount-1].screenRelativeTransitionHeight; //La dernière limite, celle où on efface le sprite, "cull".
foreach (LOD leLOD in leLODgroup.GetLODs())
{
LOD_Renderer.Add (leLOD.renderers);
foreach (Renderer leRenderer in leLOD.renderers)
{
leRenderer.enabled = false;
}
LOD_Distance.Add(niveauQualitéSpécifique*QualitySettings.lodBias*Rcull*profondeurDeChamp/leLOD.screenRelativeTransitionHeight);
LOD_Ortho.Add (niveauQualitéSpécifique*QualitySettings.lodBias*0.5f / leLOD.screenRelativeTransitionHeight); //nota : une taille orthographique de 1 correspond à un demi écran en hauteur. 0.5f pour 100% de l'écran couvert.
}
leLODgroup.enabled = false;
//Le LOD zéro est affiché par défaut.
foreach (Renderer leRenderer in leLODgroup.GetLODs () [0].renderers)
{
leRenderer.enabled = false;
}
}
void Update() {
// We don't need to update every frame, but we do need to update a few times every second.
if (_skipIndex < Skip) {
_skipIndex ++;
return;
}
else {
_skipIndex -= Skip;
}
float distance;
if (cameraActive.orthographic) //CAS ORTHOGRAPHIQUE
{
// Maintenant, seule la taille orthographique de la caméra compte pour afficher les niveaux de détail.
distance = cameraActive.orthographicSize;
if (Cutoff)
{
if (distance >= LOD_Ortho [(LOD_Ortho.Count - 1)])
{
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = false;
}
return;
}
else
{
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = true;
}
}
}
// See if the LOD needs to be increased.
if (LOD_Ortho.Count >= (_currentLOD + 1))
{
if (distance >= LOD_Ortho [_currentLOD])
{
// Change the mesh
if (LOD_Renderer.Count >= (_currentLOD + 2))
{
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = false;
}
_currentLOD++;
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = true;
}
}
}
}
// Should it be decreased?
if (_currentLOD > 0)
{
if (distance < LOD_Ortho [(_currentLOD - 1)])
{
// Change the mesh
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = false;
}
_currentLOD--;
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = true;
}
}
}
}
else //CAS PERSPECTIVE CONIQUE
{
//Je laisse tomber l'évitement des racines carrées
distance = Vector3.Distance(cameraActive.transform.position, transform.position);
if (Cutoff)
{
if (distance >= LOD_Distance [(LOD_Distance.Count - 1)])
{
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = false;
}
return;
}
else
{
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = true;
}
}
}
// See if the LOD needs to be increased.
if (LOD_Distance.Count >= (_currentLOD + 1))
{
if (distance >= LOD_Distance [_currentLOD])
{
// Change the mesh
if (LOD_Renderer.Count >= (_currentLOD + 2))
{
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = false;
}
_currentLOD++;
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = true;
}
}
}
}
// Should it be decreased?
if (_currentLOD > 0)
{
if (distance < LOD_Distance [(_currentLOD - 1)])
{
// Change the mesh
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = false;
}
_currentLOD--;
foreach (Renderer leRenderer in LOD_Renderer[_currentLOD])
{
leRenderer.enabled = true;
}
}
}
}
}
}