近段时间研究dots terrain时有个想法是给程序动态生成的mesh加上lod。网上搜了下基本国内没发现几篇讲这个的文章。官网论坛上倒是有几篇帖子。于是这里一篇记录贴。
首先来看下如果不是实时生成的网格在dots下LOD是怎么回事。我们做个试验,新建一个空的gameobject作为父entity,加上Lod Group组件和convertToEntityscirpt,然后再给这个gameobje增加3个child,分别是一个方块一个全球和一个椭圆。运行一下看看Entity debugger里面的信息。可以看见在转化生成的4个Entity中,父entity上挂接了个MeshLodGroupComponent和一个LodGroupWorldReferencePoint的组件。这个MeshLodGroupComponent用两个float4保存了8个LodDistance的参数,而另一个point组件显然是用于地址的引用。
针对3个child Entity,三个entity的组件类型完全一样,与Lod相关的组件有:MeshLodCompoent,这个也是一个定义性质的组件,包含一个对父entity的字段。
RootLODRange,最大最小参数。
LODRange,这个层级的lod对应的最大最小距离
其他组件和一个不使用lod转化的mesh entity 一样。那问题来了,这些组件似乎都没有控制entity的显示?仔细观察发现,在HybridChunkInfo中,有个visible的值。不显示的这个字段的值都被设置为0。
弄清楚dots 下LOD的数据结构有哪些后 我们尝试通过代码来给4个entity加上这些组件。不过部分组件比如LODRange不能公共访问,并不能手动添加。于是尝试给父Entity加上MeshLodGroupComponent组件,给childEntity加上MeshLodComponent组件。写个脚本测试一下:
using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.Rendering;
[DisallowMultipleComponent]
public class TestLod : MonoBehaviour, IConvertGameObjectToEntity
{
public Mesh lod0;
public Mesh lod1;
public Mesh lod2;
public Material material;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var lodGroupData = new MeshLODGroupComponent();
lodGroupData.LocalReferencePoint = float3.zero;
var lodDistances0 = new float4(float.PositiveInfinity);
var lodDistances1 = new float4(float.PositiveInfinity);
lodDistances0 = new float4(2 , 4 ,6 , 8);
lodGroupData.LODDistances0 = lodDistances0;
lodGroupData.LODDistances1 = lodDistances1;
dstManager.AddComponentData(entity , lodGroupData);
var entityLod0 = CreateRenderMeshEntity(lod0 , material , dstManager);
var entityLod1 = CreateRenderMeshEntity(lod1 , material , dstManager);
var entityLod2 = CreateRenderMeshEntity(lod2 , material , dstManager);
dstManager.AddComponentData(entityLod0 , new MeshLODComponent { Group = entity , LODMask = 1 << 0 });
dstManager.AddComponentData(entityLod1 , new MeshLODComponent { Group = entity , LODMask = 1 << 1 });
dstManager.AddComponentData(entityLod2 , new MeshLODComponent { Group = entity , LODMask = 1 << 2 });
}
public static Entity CreateRenderMeshEntity (Mesh mesh , Material material , EntityManager dstManager)
{
var desc = new RenderMeshDescription(
mesh ,
material ,
shadowCastingMode: ShadowCastingMode.On ,
receiveShadows: true
);
var prefab = dstManager.CreateEntity();
RenderMeshUtility.AddComponents(
prefab ,
dstManager ,
desc);
dstManager.AddComponentData(prefab , new LocalToWorld { Value = new float4x4(quaternion.identity , float3.zero) });
return prefab;
}
}
运行发现其他不能公开访问的组件都被加上去了,并且LOD功能显示正常。
但是从上面的分析似乎也发现了个局限性,似乎没法获取当前的LOD层级?要了解当前在哪个LOD层级,需要遍历各个子entity的HybridChunkInfo的CullingData.Visible字段。这个似乎不是一个有效率的做法。