当前LOD级别 - LOD组Unity

4

我在使用LOD Group时遇到了困难,因为我想知道我在屏幕上看到的当前活动LOD级别是哪个。我只能访问百分比信息,但无法得知具体级别。

GameObject.GetComponent<LODGroup>().GetLODs()[size].screenRelativeTransitionHeight;

有人知道如何解决这个问题吗?提前感谢。
5个回答

5

在搜索answers.unity3d.com的答案时,我找到了这个链接:http://answers.unity3d.com/questions/684467/find-the-lod-step-which-is-currently-used.html

该链接涉及如何找到当前使用的LOD步骤。
 LODGroup lodGroup = obj.GetComponent<LODGroup>();
 if (lodGroup != null)
 {
     Transform lodTransform = lodGroup.transform;
     foreach (Transform child in lodTransform)
     {
         var renderer = child.GetComponent<Renderer> ();
         if (renderer != null && renderer.isVisible)
         { 
             Debug.Log("This LODlevel is used: " + child.name); 
         }
     }
 }

您可以通过查看当前可见(在屏幕上可见)的子游戏对象渲染器的名称来确定当前活动的LOD级别。


不错,@maros。我唯一建议的是存储渲染器的引用,而不是使用GetComponent。这将使其更具性能。 - FullStackForger

4
我曾经遇到同样的问题,最终找到了一个真正有效的解决方案。(渲染器.isVisible 更新不够频繁,不能够可靠地使用,我也不想在每个LOD子物体上添加额外组件。) 我在这里上传了解决方案:https://github.com/JulienHeijmans/EditorScripts/blob/master/Scripts/Utility/Editor/LODExtendedUtility.cs ,它主要是从这里复制的代码:https://github.com/Unity-Technologies/AutoLOD/blob/master/Scripts/Extensions/LODGroupExtensions.cs,我只删除了不必要的部分,并添加了我经常使用的其他实用函数。虽然它是作为编辑器实用程序脚本来使用的,但其中包含获取当前可见LOD级别所需的数学运算。

Julien,感谢您分享您的LODExtendedUtility脚本! GetVisibleLOD方法对于调试非常有帮助。 - DizzyDoo

0
优化后的答案来自@maros:
static public int GetCurrentLODIndex(LODGroup lodGroup)
{
    LOD[] lods = lodGroup.GetLODs();
    for (int i = 0; i < lods.Length; i++)
    {
        LOD lod = lods[i];
        if (lod.renderers.Length > 0 && lod.renderers[0].isVisible)
            return i;
    }
    return -1;
}

但是如果您需要在不同的LOD中使用相同的渲染器,这种方法就不太适用。例如,我在LOD0和LOD1中使用vfx渲染器,而在LOD1中vfx被暂停。因此,根据@JulienH的答案,我使用了以下代码:
using UnityEngine;

public class LODUtils
{
/// <summary>
/// Returns the currently visible LOD level of a specific LODGroup, from a specific camera.
/// </summary>
public static int GetCurrentLODIndex(LODGroup lodGroup, Camera camera)
{
    var lods = lodGroup.GetLODs();
    var relativeHeight = GetRelativeHeight(lodGroup, camera);

    int lodIndex = GetMaxLOD(lodGroup);
    for (var i = 0; i < lods.Length; i++)
    {
        var lod = lods[i];

        if (relativeHeight >= lod.screenRelativeTransitionHeight)
        {
            lodIndex = i;
            break;
        }
    }

    return lodIndex;
}

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));
}

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;
}

private static int GetMaxLOD(LODGroup lodGroup)
{
    return lodGroup.lodCount - 1;
}

private static float GetWorldSpaceSize(LODGroup lodGroup)
{
    return GetWorldSpaceScale(lodGroup.transform) * lodGroup.size;
}

private static float GetWorldSpaceScale(Transform t)
{
    var scale = t.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;
}
}

-2
private static int GetLODCurShowLevel(Camera cam, LODGroup lodGroup)
{
    //var inv_SceneViewCamHeight = 1.0f / (cam.pixelHeight - 6.0f);
    var inv_SceneViewCamHeight = 1.0f / (cam.pixelHeight);

    var lods = lodGroup.GetLODs();
    for (int lodIDX = 0; lodIDX < lods.Length; lodIDX++)
    {
        var lod = lods[lodIDX];
        var renderers = lod.renderers;
        for (int renderIDX = 0; renderIDX < renderers.Length; renderIDX++)
        {
            var renderer = renderers[renderIDX];

            // method1:
            //var heightInScreen = Mathf.Abs(cam.WorldToScreenPoint(renderer.bounds.max).y - cam.WorldToScreenPoint(renderer.bounds.min).y);

            // method2:
            var heightInScreen = GetHeightInScreen(cam, renderer);
            var ratioInScren = heightInScreen * inv_SceneViewCamHeight;
            if (ratioInScren > lod.screenRelativeTransitionHeight)
            {
                return lodIDX;
            }
        }
    }

    return -1;
}

private static float GetHeightInScreen(Camera cam, Renderer renderer)
{
    var min = renderer.bounds.min;
    var max = renderer.bounds.max;
    // F = Front
    var FTL = new Vector3(min.x, max.y, min.z);
    var FTR = new Vector3(max.x, max.y, min.z);
    var FBR = new Vector3(max.x, min.y, min.z);
    var FBL = new Vector3(min.x, min.y, min.z);

    // Back
    var BTL = new Vector3(min.x, max.y, max.z);
    var BTR = new Vector3(max.x, max.y, max.z);
    var BBR = new Vector3(max.x, min.y, max.z);
    var BBL = new Vector3(min.x, min.y, max.z);

    // to screen space pos
    FTL = cam.WorldToScreenPoint(FTL);
    FTR = cam.WorldToScreenPoint(FTR);
    FBR = cam.WorldToScreenPoint(FBR);
    FBL = cam.WorldToScreenPoint(FBL);

    BTL = cam.WorldToScreenPoint(BTL);
    BTR = cam.WorldToScreenPoint(BTR);
    BBR = cam.WorldToScreenPoint(BBR);
    BBL = cam.WorldToScreenPoint(BBL);

    var maxY = FTL.y;
    maxY = Mathf.Max(FTR.y, maxY);
    maxY = Mathf.Max(FBR.y, maxY);
    maxY = Mathf.Max(FBL.y, maxY);

    maxY = Mathf.Max(BTL.y, maxY);
    maxY = Mathf.Max(BTR.y, maxY);
    maxY = Mathf.Max(BBR.y, maxY);
    maxY = Mathf.Max(BBL.y, maxY);

    var minY = FTL.y;
    minY = Mathf.Min(FTR.y, minY);
    minY = Mathf.Min(FBR.y, minY);
    minY = Mathf.Min(FBL.y, minY);

    minY = Mathf.Min(BTL.y, minY);
    minY = Mathf.Min(BTR.y, minY);
    minY = Mathf.Min(BBR.y, minY);
    minY = Mathf.Min(BBL.y, minY);

    return maxY - minY;
}

-2
public class TestingStoreLODGroupCurLODLevel : MonoBehaviour
{
    public bool[] lodVisibleArr;
    public int GetCurLOD()
    {
        if (lodVisibleArr != null)
        {
            var len = lodVisibleArr.Length;
            for (int i = 0; i < len; i++)
            {
                if (lodVisibleArr[i])
                {
                    return i;
                }
            }
        }
        return -1;
    }
}

public class TestingCheckVisibleChanged : MonoBehaviour
{
    public int belongLOD;
    public TestingStoreLODGroupCurLODLevel storeLOD;
    private void OnBecameInvisible()
    {
        if (storeLOD)
        {
            storeLOD.lodVisibleArr[belongLOD] = false;
        }
    }

    private void OnBecameVisible()
    {
        if (storeLOD)
        {
            storeLOD.lodVisibleArr[belongLOD] = true;
        }
    }
}

    private void SetupCheckLODInfo(GameObject go)
    {
        var lodGroup = go.GetComponent<LODGroup>();
        if (lodGroup == null)
        {
            return;
        }

        var storeLODComp = go.GetComponent<TestingStoreLODGroupCurLODLevel>();
        if (storeLODComp != null)
        {
            return;
        }

        storeLODComp = go.AddComponent<TestingStoreLODGroupCurLODLevel>();
        var lods = lodGroup.GetLODs();
        for (int lodIDX = 0; lodIDX < lods.Length; lodIDX++)
        {
            var lod = lods[lodIDX];
            var renderers = lod.renderers;
            for (int rendererIDX = 0; rendererIDX < renderers.Length; rendererIDX++)
            {
                var renderer = renderers[rendererIDX];
                var checkVisibleComp = renderer.gameObject.GetComponent<TestingCheckVisibleChanged>();
                if (checkVisibleComp == null)
                {
                    checkVisibleComp = renderer.gameObject.AddComponent<TestingCheckVisibleChanged>();
                }
                checkVisibleComp.belongLOD = lodIDX;
                checkVisibleComp.storeLOD = storeLODComp;
            }
        }

        storeLODComp.lodVisibleArr = new bool[lods.Length]; 
    }

    private void UnSetupCheckLODInfo(GameObject go)
    {
        var lodGroup = go.GetComponent<LODGroup>();
        if (lodGroup == null)
        {
            return;
        }
        var storeLODComp = go.GetComponent<TestingStoreLODGroupCurLODLevel>();
        if (storeLODComp != null)
        {
            GameObject.Destroy(storeLODComp);
        }

        var lods = lodGroup.GetLODs();
        for (int lodIDX = 0; lodIDX < lods.Length; lodIDX++)
        {
            var lod = lods[lodIDX];
            var renderers = lod.renderers;
            for (int rendererIDX = 0; rendererIDX < renderers.Length; rendererIDX++)
            {
                var renderer = renderers[rendererIDX];
                var checkVisibleComp = renderer.gameObject.GetComponent<TestingCheckVisibleChanged>();
                if (checkVisibleComp != null)
                {
                    GameObject.Destroy(checkVisibleComp);
                }
            }
        }
    }

请编辑您的答案,解释您的代码是如何解决问题的。 - BDL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接