Unity: gestión de LOD para objetos de carácter


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
inserte la descripción de la imagen aquí

Pero podemos cambiar la cuadrícula de acuerdo con la distancia nosotros mismos.
inserte la descripción de la imagen aquí


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

Supongo que te gusta

Origin blog.csdn.net/linjf520/article/details/122116464
Recomendado
Clasificación