Directorio de artículos
Unity no tiene gestión de LOD de personalidad integrada
Haciendo referencia a un hilo en el foro de Unity: Gestión de nivel de detalle (LOD)
Aunque Unity no tiene una gestión de LOD de caracteres integrada
Pero podemos cambiar la cuadrícula de acuerdo con la distancia nosotros mismos.
Puedes escribir tu propio script para controlarlo a distancia.
Referencia directa: https://pastebin.com/clone/K1S4Zjh0
using UnityEngine;
using System;
using System.Collections.Generic;
//[ExecuteInEditMode]
public class CharacterLOD : MonoBehaviour
{
public Mesh LOD0;
public Mesh LOD1;
public Mesh LOD2;
public Mesh LOD3;
public List<Material> LOD_0_Materials;
public List<Material> LOD_1_Materials;
public List<Material> LOD_2_Materials;
public List<Material> LOD_3_Materials;
public float lod0Dist = 10f;
public float lod1Dist = 20f;
public float lod2Dist = 30f;
public float lod3Dist = 50f;
public float lodTimer = 0.3f;
public Camera camera1;
private bool foundCamera;
public int currLOD;
private float currTimer;
public void Start()
{
GetCamera();
currLOD = 0;
}
void Update()
{
if (foundCamera == false)
GetCamera();
//Update LODs Timer
currTimer -= Time.deltaTime;
if (currTimer <= 0.0f)
{
UpdateMeshLOD();
currTimer = lodTimer; //Reset Timer
}
}
public void UpdateMeshLOD()
{
if (camera1 == null) return;
Vector3 camPos1 = camera1.transform.position;
if ((transform.position - camPos1).sqrMagnitude < (lod0Dist * QualitySettings.lodBias) * (lod0Dist * QualitySettings.lodBias)) //LOD 0
{
if (currLOD != 0)
{
SetLowestLODMesh(QualitySettings.maximumLODLevel);
SetLODMaterials(QualitySettings.maximumLODLevel);
currLOD = 0;
return;
}
}
else if ((transform.position - camPos1).sqrMagnitude < (lod1Dist * QualitySettings.lodBias) * (lod1Dist * QualitySettings.lodBias)) //LOD 1
{
if (currLOD != 1)
{
SetLowestLODMesh(QualitySettings.maximumLODLevel + 1);
SetLODMaterials(GetLowestLODMats(QualitySettings.maximumLODLevel + 1));
currLOD = 1;
return;
}
}
else if ((transform.position - camPos1).sqrMagnitude < (lod2Dist * QualitySettings.lodBias) * (lod2Dist * QualitySettings.lodBias)) //LOD 2
{
if (currLOD != 2)
{
SetLowestLODMesh(QualitySettings.maximumLODLevel + 2);
SetLODMaterials(GetLowestLODMats(QualitySettings.maximumLODLevel + 2));
currLOD = 2;
return;
}
}
else if ((transform.position - camPos1).sqrMagnitude < (lod3Dist * QualitySettings.lodBias) * (lod3Dist * QualitySettings.lodBias)) //LOD 3
{
if (currLOD != 3)
{
SetLowestLODMesh(QualitySettings.maximumLODLevel + 3);
SetLODMaterials(GetLowestLODMats(QualitySettings.maximumLODLevel + 3));
currLOD = 3;
return;
}
}
}
public void SetLODMaterials(int lod)
{
Material[] currMats;
bool wasSuccess = false;
switch (lod)
{
case 0: //LOD 0
if (LOD_0_Materials.Count > 0)
{
int existingMatsCount = 0;
currMats = new Material[LOD_0_Materials.Count];
for (var x = 0; x < LOD_0_Materials.Count; x++)
{
currMats[x] = LOD_0_Materials[x];
if (LOD_0_Materials[x] != null)
existingMatsCount++;
}
if (existingMatsCount / LOD_0_Materials.Count > 0.5f) //Atleast 50% of materials exist
{
GetComponent<Renderer>().sharedMaterials = currMats;
wasSuccess = true;
}
}
break;
case 1:
if (LOD_1_Materials.Count > 0)
{
int existingMatsCount = 0;
currMats = new Material[LOD_1_Materials.Count];
for (var x = 0; x < LOD_1_Materials.Count; x++)
{
currMats[x] = LOD_1_Materials[x];
if (LOD_1_Materials[x] != null)
existingMatsCount++;
}
if (existingMatsCount / LOD_1_Materials.Count > 0.5f) //Atleast 50% of materials exist
{
GetComponent<Renderer>().sharedMaterials = currMats;
wasSuccess = true;
}
}
break;
case 2:
if (LOD_2_Materials.Count > 0)
{
int existingMatsCount = 0;
currMats = new Material[LOD_2_Materials.Count];
for (var x = 0; x < LOD_2_Materials.Count; x++)
{
currMats[x] = LOD_2_Materials[x];
if (LOD_2_Materials[x] != null)
existingMatsCount++;
}
if (existingMatsCount / LOD_2_Materials.Count > 0.5f) //Atleast 50% of materials exist
{
GetComponent<Renderer>().sharedMaterials = currMats;
wasSuccess = true;
}
}
break;
case 3:
if (LOD_3_Materials.Count > 0)
{
int existingMatsCount = 0;
currMats = new Material[LOD_3_Materials.Count];
for (var x = 0; x < LOD_3_Materials.Count; x++)
{
currMats[x] = LOD_3_Materials[x];
if (LOD_3_Materials[x] != null)
existingMatsCount++;
}
if (existingMatsCount / LOD_3_Materials.Count > 0.5f) //Atleast 50% of materials exist
{
GetComponent<Renderer>().sharedMaterials = currMats;
wasSuccess = true;
}
}
break;
}
if (wasSuccess)
Debug.Log("[CharacterLOD] " + this.transform.root.name + " Swapped LOD Mats to: " + lod);
}
public int GetLowestLODMats(int desired)
{
if (desired >= 3)
{
if (LOD_3_Materials.Count > 0)
return 3;
if (LOD_2_Materials.Count > 0)
return 2;
if (LOD_1_Materials.Count > 0)
return 1;
if (LOD_0_Materials.Count > 0)
return 0;
}
if (desired == 2)
{
if (LOD_2_Materials.Count > 0)
return 2;
if (LOD_1_Materials.Count > 0)
return 1;
if (LOD_0_Materials.Count > 0)
return 0;
}
if (desired == 1)
{
if (LOD_1_Materials.Count > 0)
return 1;
if (LOD_0_Materials.Count > 0)
return 0;
}
if (desired == 0)
{
if (LOD_0_Materials.Count > 0)
return 0;
}
return 0;
}
public void SetLowestLODMesh(int desired)
{
SkinnedMeshRenderer mf1 = GetComponent<SkinnedMeshRenderer>();
if (desired >= 3)
{
if (LOD3 != null)
mf1.sharedMesh = LOD3;
if (LOD2 != null)
mf1.sharedMesh = LOD2;
if (LOD1 != null)
mf1.sharedMesh = LOD1;
if (LOD0 != null)
mf1.sharedMesh = LOD0;
}
if (desired == 2)
{
if (LOD2 != null)
mf1.sharedMesh = LOD2;
if (LOD1 != null)
mf1.sharedMesh = LOD1;
if (LOD0 != null)
mf1.sharedMesh = LOD0;
}
if (desired == 1)
{
if (LOD1 != null)
mf1.sharedMesh = LOD1;
if (LOD0 != null)
mf1.sharedMesh = LOD0;
}
if (desired == 0)
if (LOD0 != null)
mf1.sharedMesh = LOD0;
}
public void GetCamera()
{
try
{
camera1 = Camera.main;
foundCamera = true;
}
catch (Exception e)
{
Debug.Log("[CharacterLOD] Couldn't find Main Camera: " + e.Message);
}
}
}
extensión y sus problemas
Habrá algunos problemas si lo anterior se maneja a distancia.
Por ejemplo, no es muy útil en juegos FPS.
Porque el juego tendrá una lupa.
La lupa generalmente se ajusta FOV para hacer frente a
Si se procesa de acuerdo con la relación de altura de la pantalla cuando se procesa en LODGroup, no hay problema en este tipo de producción.
Pero cuando el método LODGROUP no está configurado para tratar con SkinnedMeshRenderer
Porque el estado de la información de animación dentro de SkinnedMeshRenderer
Por lo tanto, solo puede escribir un script para cambiar la malla, simplemente no mueva la información del hueso de animación.
Luego, combínelo con el valor de FOV para convertirlo, de modo que el LOD de SknnedMeshRnederer se pueda mostrar normalmente en diferentes tamaños de FOV.
Hay otro problema, ninguno de los métodos anteriores puede cambiar la estructura ósea
Porque si la estructura ósea de un modelo es muy compleja, también consumirá mucho dinero.
Pero en teoría, podemos escribir otro: al cambiar el LOD nuevamente, puede sincronizar el estado de Animator del LOD anterior y AnimationClip.playTime con el LOD actual, pero no hay garantía de que se mueva o no, depende de el paquete API no es lo suficientemente bueno
Referencias
- Creación de un grupo LOD para el personaje
- Gestión de nivel de detalle (LOD)
- Unity genera automáticamente LOD, y el uso de LOD para personajes humanoides resuelve el problema de la reproducción de animación : este método no es muy bueno, todavía hay fluctuaciones de movimiento cuando se cambia el LOD del personaje, pero el complemento de generación de modelo LOD interno puede ser usado