之前用Unity的LOD Group一直都是简单用了一下,今天才发现有好几个认知都是错误的,需要重新认识下LODGroup
LODGroup百分比并不是简单的距离百分比
之前以为LOD就是根据距离的远近然后切换的,LODGroup上面的百分比是距离的百分比,因此也一直很疑惑,这个距离的基准是多少,在哪里设置也没有找到。 而事实上,这个百分比是边界(Bounds)占屏幕的大小比,与距离有一定关系,但距离只是其中一个计算因子。 其实,我们仔细想想,就会发现如果用距离作为标准的话,每一个物体几乎都得设置自己的LOD切换分界值,因为对于巨大的物体,即使距离远了,但可能在屏幕上的大小依然很大,对于较小的物体,即使距离近了,在屏幕上也是很小,这样子的话设置LOD就会比较复杂。而使用占屏幕的大小比,就可以得到一个大体一致的标准。 从Gizmos也可以看得出来
从代码上 虽然LODGroup的代码基本看不了,都是内部方法,但它的Editor代码还是有一些信息的 根据我们设置的百分比,去倒推所需要的摄象机距离,然后再根据相机的正交还是透视的设置,去设置场景相机的设置
LODGroupEditor.cs
private static void UpdateCamera(float desiredPercentage, LODGroup group)
{
var worldReferencePoint = LODUtility.CalculateWorldReferencePoint(group);
var percentage = Mathf.Max(desiredPercentage / QualitySettings.lodBias, 0.000001f);
var sceneView = SceneView.lastActiveSceneView;
var sceneCamera = sceneView.camera;
var distance = LODUtility.CalculateDistance(sceneCamera, percentage, group);
float size;
if (sceneCamera.orthographic)
{
size = distance;
if (sceneCamera.aspect < 1.0)
size *= sceneCamera.aspect;
}
else
{
var fov = sceneCamera.fieldOfView;
size = distance * Mathf.Sin(fov * 0.5f * Mathf.Deg2Rad);
}
SceneView.lastActiveSceneView.LookAtDirect(worldReferencePoint, sceneCamera.transform.rotation, size);
}
倒推距离的方法,我们从参数名relativeScreenHeight就可以看出来,用的是相对屏幕的高度,就是边界高/屏幕高 LODUtility.bindings.cs
[FreeFunction("LODUtilityBindings::CalculateDistance")]
extern internal static float CalculateDistance(Camera camera, float relativeScreenHeight, LODGroup group);
LOD Bias的真正意义
之前看资料时,大部分的文档都是和官方文档差不多的描述,意思是那么个意思,但总感觉不是很清楚 看了下面源码中的这一句,其实就很好理解了,其实LOD Bias就是一个缩放倍数,
var percentage = Mathf.Max(desiredPercentage / QualitySettings.lodBias, 0.000001f);
比如原来我们设定的100%-50%显示LOD0,如果我们设置LOD Bias为2,那就是实际边界高占屏幕比时50%-25%时显示LOD0,但由于向上没有更高的LOD,所以最后是100%-25%显示LOD0, 或者换个思路理解,LOD Bias为1时,基准100%就是100% 而LOD Bias为2时,基准100%,实际对应的比值只有50%了,后面所有的比值界线都得除以2
Maximum LOD Level 有点鸡肋
看Maximum LOD Level的文档描述还以为这是个高级功能,能够快速的实现内存的优化,但实际挺鸡肋的 根据测试结果: 对AssetBundle无优化:不会减少AssetBundle的加载,所有级别的AB都会关联加载 对Mesh的加载优化很小:只要有设置0,所有级别的Mesh都会被加载,只有将最高级质量级别设置为1,那么0级的Mesh才不会被加载,以此类推 所以这个功能有点鸡肋,原来还想用在对移动端的设备分级,但这样就一点效果都没有 或许就像文档里描述的,对不同平台有些作用,比如PC平台有LOD0-LOD2,而移动端平台只有LOD1-LOD2,这样可以启到一小点优化作用 不知道是不是我们没有发现真正的用法,但目前测试的事实如此,有大佬路过还请指导一下 目前后续是准备让美术场景中用Unity的LODGroup,然后导出时再换成自己的LOD组件
一些有价值的参考代码
private static int GetLODCurShowLevel(Camera cam, LODGroup lodGroup)
{
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];
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;
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);
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);
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;
}
参考
http://blog.coolcoding.cn/?p=709 https://stackoverflow.com/questions/37755510/current-lod-level-lod-group-unity https://github.com/JulienHeijmans/EditorScripts/blob/8482fea14852ce8032ed50060ab18557ce15f984/Scripts/Utility/Editor/LODExtendedUtility.cs#L84
|