ECS ECS实体与普通对象的性能对比

  • 准备工作

    • 改变实体的Transform

新建一个System,尝试控制实体的位置偏移,控制Translation组件,这个是Unity自身Transform下的默认组件

改变实体位置

public class TestConterollerComponten : ComponentSystem {
    protected override void OnUpdate()
    {
        Entities.ForEach((ref Translation translation) =>
        {
            translation.Value = new Unity.Mathematics.float3(1, 1, 1);
        });
    }
}

改变实体角度

把一个GameObject转成Entity后,Translation组件它默认是拥有的,但是RotationEulerXYZ 角度组件需要我们手动添加

上一章我们讲过,要用代理类,添加我们写的数据组件,RotationEulerXYZ 也是一样的

代理类

public class TestTransformCorrelation : MonoBehaviour, IConvertGameObjectToEntity
{
    public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
        dstManager.AddComponentData(entity, new RotationEulerXYZ());
    }
}

修改实体的角度 

 
public class TestConterollerComponten : ComponentSystem {
    protected override void OnUpdate()
    {
        Entities.ForEach((ref RotationEulerXYZ RotationEulerXYZ) =>
        {
            RotationEulerXYZ.Value = new Unity.Mathematics.float3(0,45,0);
        });
    }
}

使用ECS预制件生成1w个方块

  • 首先新建一个Cube ,并把它设置成预制件
  • 新建一个控制脚本Manager,这一部分跟着写就可以了,后面会对EntityManager的API做更多的介绍 
public GameObject cube;

public float interval, sum;

void Start () {

        // 把普通预制件转成ECS预制件
		GameObjectConversionSettings tempSetting = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld,null);
		Entity tempEntityPrefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(cube, tempSetting);
        
        // 获得EntityManager
		EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

		Translation tempTranslation = new Translation();
		tempTranslation.Value.x = -1;
		for (int i = 0; i < sum; i++)
        {
            for (int j = 0; j < sum; j++)
            {
                // 生成实体
				Entity entityCube = entityManager.Instantiate(tempEntityPrefab);
				tempTranslation.Value.x += interval;
                // 使用EntityManager,修改实体的位置
				entityManager.SetComponentData(entityCube, tempTranslation);
			}
			tempTranslation.Value.x =-1;
			tempTranslation.Value.y += interval;
		}
		

}
  • 把预制件拖进脚本里
  • 间隔interval设置成2,sum设置100,这样就把1w个方块平铺排开了

使用普通方式生成1W个方块

public GameObject cubePrefab;
	public float interval, sum;
	void Start()
	{
		Vector3 tempVector3 = new Vector3(-interval,0,0);
		for (int i = 0; i < sum; i++)
		{
			for (int j = 0; j < sum; j++)
			{
				//GameObject entityCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
				GameObject entityCube = GameObject.Instantiate(cubePrefab);
				tempVector3.x += interval;
				entityCube.transform.position = tempVector3;
			}
			tempVector3.x = -1;
			tempVector3.y += interval;
		}


}

运行后性能对比

同样是生成一万个方块,让相机渲染到所有方块

普通方式fps只有70

扫描二维码关注公众号,回复: 14669966 查看本文章

ECS生成fps翻了一倍

 通过JobSystem和Burst编译器进一步优化性能

 我们新建一个JobSystem,我们在通过Entities把所有的方块的Burst打开

运行后fps应该会再提升一点

public class ECSJobComponentSystem : JobComponentSystem
{
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        JobHandle tempJobHandle = Entities.ForEach((ref Translation translation ) =>{})
                   //打开Burst
                   .WithBurst()
                   .Schedule(inputDeps);
        return tempJobHandle;
    }
}

使用批处理处理GpuInstancing优化性能

CPU----数据---->GPU----渲染---->屏幕

游戏内对象越多,需要提交的数据就越多,批处理就是打包多个数据成一个数据提交,降低数据提交次数

批处理有静态\动态\GpuInstancing三种

  •  还是在ECS的基础上 1w个cube渲染,需要我们新建一个材质球,给材质球打开批处理

FPS到了360多,又涨了一倍多,整体性能翻倍 

  • 那么如果只是用批处理,不用ECS,性能会有这么大的提升么?

开了批处理,性能肯定是有所提升的,我用普通的生成方式,生成1w个方块,也同时给这些方块的材质球打开了批处理,fps从70提升到了80左右

所以主要还是ESC对性能的帮助,才能让Unity运行速度更起飞

猜你喜欢

转载自blog.csdn.net/Liu_ChangC/article/details/125077273
ECS