【Unity】万人同屏, 从入门到放弃之——Entities 1.0.16性能测试

这篇具有很好参考价值的文章主要介绍了【Unity】万人同屏, 从入门到放弃之——Entities 1.0.16性能测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当前测试使用的Entities版本为1.0.16

Unity Entities 1.0.16使用方法:

Create a component for the spawner example | Entities | 1.0.16

1. 创建SubScene

【Unity】万人同屏, 从入门到放弃之——Entities 1.0.16性能测试,Unity,unity,游戏引擎

2. 在SubScene下创建挂载Authoring脚本:

Authoring是MonoBehaviour脚本,主要用来序列化配置需要创建的实体prefab资源或参数;

因为Entities目前不支持用资源名动态加载资源!没错,AssetsBundle或Addressables都不能用于Entities;也就意味着现阶段不能用Entities开发DLC或热更游戏。

Entities必须使用SubScene,而SubScene不能从资源动态加载,路被彻底封死了。

public class EntitiesAuthoring : MonoBehaviour
{
    public GameObject m_Prefab;
    public int m_Row;
    public int m_Col;
}

 3. 把步骤2的挂有Authoring脚本的GameObject转换为Entity:

SubScene中挂载的MonoBehaviour不会被执行,必须转换为Entity;

此步骤主要是把Authoring中的参数转接到自己定义的ComponentData;


class EntitiesAuthoringBaker : Baker<EntitiesAuthoring>
{
    public override void Bake(EntitiesAuthoring authoring)
    {
        var entity = GetEntity(TransformUsageFlags.None);
        AddComponent<EntitiesComponentData>(entity, new EntitiesComponentData
        {
            m_PrefabEntity = GetEntity(authoring.m_Prefab, TransformUsageFlags.Dynamic | TransformUsageFlags.Renderable),
            m_Row = authoring.m_Row,
            m_Col = authoring.m_Col
        });
    }
}

struct EntitiesComponentData : IComponentData
{
    public Entity m_PrefabEntity;
    public int m_Row;
    public int m_Col;
}

 4. 编写创建Entity的System脚本:

由于MonoBehaviour不会在SubScene中执行,System就类似MonoBehavior,拥有OnCreate, OnUpdate, OnDestroy生命周期。Entities框架会自动执行所有已经定义的System,若不想自动执行System可以在头部添加[DisableAutoCreation],然后使用state.World.CreateSystem<MoveEntitiesSystem>()手动创建System。

[BurstCompile]
partial struct SpawnEntitiesSystem : ISystem
{
    void OnCreate(ref SystemState state)
    {
        //Application.targetFrameRate = 120;
        state.RequireForUpdate<EntitiesComponentData>();
    }
    void OnDestroy(ref SystemState state)
    {

    }

    void OnUpdate(ref SystemState state)
    {
        var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
        var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);

        foreach (var data in SystemAPI.Query<EntitiesComponentData>())
        {
            Unity.Mathematics.Random m_Random = new Unity.Mathematics.Random(1);
            var m_RandomRange = new float4(-data.m_Row * 0.5f, data.m_Row * 0.5f, -data.m_Col * 0.5f, data.m_Col * 0.5f);
            var halfSize = new float2(data.m_Col * 0.5f, data.m_Row * 0.5f);
            for (int i = 0; i < data.m_Row; i++)
            {
                for (int j = 0; j < data.m_Col; j++)
                {
                    var entity = state.EntityManager.Instantiate(data.m_PrefabEntity);
                    ecb.SetComponent(entity, LocalTransform.FromPosition(new float3(j - halfSize.x, 0, i - halfSize.y)));
                    ecb.AddComponent<TargetMovePointData>(entity, new TargetMovePointData() { targetPoint = new float3(m_Random.NextFloat(m_RandomRange.x, m_RandomRange.y), 0, m_Random.NextFloat(m_RandomRange.z, m_RandomRange.w)) });
                }
            }
            state.Enabled = false;
        }
    }
}

 5. 定义一个System专门控制所有小人的移动:

使用JobSystem并行计算和设置小人的位置:

[BurstCompile]
    partial struct MoveEntitiesJob : IJobParallelFor
    {
        [ReadOnly]
        public Unity.Mathematics.Random random;
        [ReadOnly]
        public float4 randomRange;

        [ReadOnly]
        public float moveSpeed;

        [ReadOnly]
        public NativeArray<Entity> entities;
        [NativeDisableParallelForRestriction]
        public EntityManager entityManager;
        [WriteOnly]
        public EntityCommandBuffer.ParallelWriter entityWriter;

        [BurstCompile]
        public void Execute(int index)
        {
            var entity = entities[index];
            var tPointData = entityManager.GetComponentData<TargetMovePointData>(entity);
            var tPoint = tPointData.targetPoint;
            var transform = entityManager.GetComponentData<LocalTransform>(entity);

            float3 curPoint = transform.Position;
            var offset = tPoint - curPoint;
            if (math.lengthsq(offset) < 0.4f)
            {
                tPointData.targetPoint = new float3(random.NextFloat(randomRange.x, randomRange.y), 0, random.NextFloat(randomRange.z, randomRange.w));
                entityWriter.SetComponent(index, entity, tPointData);
            }

            float3 moveDir = math.normalize(tPointData.targetPoint - curPoint);
            transform.Rotation = Quaternion.LookRotation(moveDir);
            transform.Position += moveDir * moveSpeed;
            entityWriter.SetComponent(index, entity, transform);
        }
    }

 Entities测试结果:

10万个移动的小人,140多帧,同等数量级比自定义BatchRendererGroup帧数高出20+,那是因为Entities Graphics内部实现了BatchRendererGroup的剔除Culling,相机视口外的物体会被Culling。自定义BatchRendererGroup只要在OnPerformCulling回调方法中实现Culling也能达到相同的性能:

【Unity】万人同屏, 从入门到放弃之——Entities 1.0.16性能测试,Unity,unity,游戏引擎

 其实到这里测试已经没有意义了,GPU端Entities Graphics结局已经注定,所谓Entities ECS结构也只是对CPU的性能提升,但海量物体的渲染GPU是最大的瓶颈。

使用Entities 1.0.16安卓端性能:

1万个小人,12帧;

【Unity】万人同屏, 从入门到放弃之——Entities 1.0.16性能测试,Unity,unity,游戏引擎

 查了查URP的渲染实现,其实内部也是Batch Renderer Group, 所以这也注定了无论是自定义Batch Renderer Group还是使用Entities,在移动端都是一样的性能。

扩展讨论:

Unity是支持配置Android端多线程策略的,Android CPU大小核性能差距巨大,大核性能强劲但耗电量大,小核弱鸡但省电,如果Jobs分配到小核执行会比主线程还慢,就会导致负优化。

既然万人同屏延迟主要在渲染线程,那么能否通过配置只允许渲染线程用大核心呢?(或者Unity默认策略就是这样的);

可以参考:Unity - Manual: Android thread configuration对Android线程策略进行配置。

结论:

目前为止(Entities 1.0.16)有太多致命局限性,也只是对PC平台做了性能优化,并且有开挂般的大幅提升;

但是对于移动平台收效甚微,JobSystem在移动平台并行线程数迷之变少,并且暂无开放接口设置。图形库必须为OpenGLES3及以上或Vulkan,与使用限制和开发门槛相比,ECS结构微弱的性能提升不值一提。

移动平台万人同屏方案尝试失败,弃坑。不过苍蝇再小也是肉,单线程的Unity编程方式早已跟不上如今的硬件发展,虽然HybridCLR不支持Burst加速,只能以解释方式执行JobSystem,但是安全的多线程对大量数据的计算仍然有很大的意义。

期待Entities的资源系统早日面世...

最后附上Entities万人同屏测试代码:文章来源地址https://www.toymoban.com/news/detail-726226.html

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.Jobs;

public class EntitiesAuthoring : MonoBehaviour
{
    public GameObject m_Prefab;
    public int m_Row;
    public int m_Col;
}

class EntitiesAuthoringBaker : Baker<EntitiesAuthoring>
{
    public override void Bake(EntitiesAuthoring authoring)
    {
        var entity = GetEntity(TransformUsageFlags.None);
        AddComponent<EntitiesComponentData>(entity, new EntitiesComponentData
        {
            m_PrefabEntity = GetEntity(authoring.m_Prefab, TransformUsageFlags.Dynamic | TransformUsageFlags.Renderable),
            m_Row = authoring.m_Row,
            m_Col = authoring.m_Col
        });
    }
}

struct EntitiesComponentData : IComponentData
{
    public Entity m_PrefabEntity;
    public int m_Row;
    public int m_Col;
}
[BurstCompile]
partial struct SpawnEntitiesSystem : ISystem
{
    void OnCreate(ref SystemState state)
    {
        //Application.targetFrameRate = 120;
        state.RequireForUpdate<EntitiesComponentData>();
    }
    void OnDestroy(ref SystemState state)
    {

    }

    void OnUpdate(ref SystemState state)
    {
        var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
        var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);

        foreach (var data in SystemAPI.Query<EntitiesComponentData>())
        {
            Unity.Mathematics.Random m_Random = new Unity.Mathematics.Random(1);
            var m_RandomRange = new float4(-data.m_Row * 0.5f, data.m_Row * 0.5f, -data.m_Col * 0.5f, data.m_Col * 0.5f);
            var halfSize = new float2(data.m_Col * 0.5f, data.m_Row * 0.5f);
            for (int i = 0; i < data.m_Row; i++)
            {
                for (int j = 0; j < data.m_Col; j++)
                {
                    var entity = state.EntityManager.Instantiate(data.m_PrefabEntity);
                    ecb.SetComponent(entity, LocalTransform.FromPosition(new float3(j - halfSize.x, 0, i - halfSize.y)));
                    ecb.AddComponent<TargetMovePointData>(entity, new TargetMovePointData() { targetPoint = new float3(m_Random.NextFloat(m_RandomRange.x, m_RandomRange.y), 0, m_Random.NextFloat(m_RandomRange.z, m_RandomRange.w)) });
                }
            }
            state.Enabled = false;
            
        }
    }
    [BurstCompile]
    partial struct MoveEntitiesSystem : ISystem
    {
        Unity.Mathematics.Random m_Random;
        float4 m_RandomRange;
        void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<TargetMovePointData>();
        }
        void OnStartRunning(ref SystemState state)
        {
            if (SystemAPI.TryGetSingleton<EntitiesComponentData>(out var dt))
            {
                m_RandomRange = new float4(-dt.m_Row * 0.5f, dt.m_Row * 0.5f, -dt.m_Col * 0.5f, dt.m_Col * 0.5f);
            }
            else
            {
                m_RandomRange = new float4(-50, 50, -50, 50);
            }
        }
        void OnDestroy(ref SystemState state)
        {

        }

        void OnUpdate(ref SystemState state)
        {
            EntityCommandBuffer.ParallelWriter ecb = GetEntityCommandBuffer(ref state);
            m_Random = new Unity.Mathematics.Random((uint)Time.frameCount);
            var entityQuery = SystemAPI.QueryBuilder().WithAll<TargetMovePointData>().Build();
            var tempEntities = entityQuery.ToEntityArray(Allocator.TempJob);

            var moveJob = new MoveEntitiesJob
            {
                random = m_Random,
                moveSpeed = SystemAPI.Time.DeltaTime * 4,
                randomRange = m_RandomRange,
                entities = tempEntities,
                entityManager = state.EntityManager,
                entityWriter = ecb
            };
            var moveJobHandle = moveJob.Schedule(tempEntities.Length, 64);
            moveJobHandle.Complete();
        }
        private EntityCommandBuffer.ParallelWriter GetEntityCommandBuffer(ref SystemState state)
        {
            var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
            var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);
            return ecb.AsParallelWriter();
        }
    }
    struct TargetMovePointData : IComponentData
    {
        public float3 targetPoint;
    }
    [BurstCompile]
    partial struct MoveEntitiesJob : IJobParallelFor
    {
        [ReadOnly]
        public Unity.Mathematics.Random random;
        [ReadOnly]
        public float4 randomRange;

        [ReadOnly]
        public float moveSpeed;

        [ReadOnly]
        public NativeArray<Entity> entities;
        [NativeDisableParallelForRestriction]
        public EntityManager entityManager;
        [WriteOnly]
        public EntityCommandBuffer.ParallelWriter entityWriter;

        [BurstCompile]
        public void Execute(int index)
        {
            var entity = entities[index];
            var tPointData = entityManager.GetComponentData<TargetMovePointData>(entity);
            var tPoint = tPointData.targetPoint;
            var transform = entityManager.GetComponentData<LocalTransform>(entity);

            float3 curPoint = transform.Position;
            var offset = tPoint - curPoint;
            if (math.lengthsq(offset) < 0.4f)
            {
                tPointData.targetPoint = new float3(random.NextFloat(randomRange.x, randomRange.y), 0, random.NextFloat(randomRange.z, randomRange.w));
                entityWriter.SetComponent(index, entity, tPointData);
            }

            float3 moveDir = math.normalize(tPointData.targetPoint - curPoint);
            transform.Rotation = Quaternion.LookRotation(moveDir);
            transform.Position += moveDir * moveSpeed;
            entityWriter.SetComponent(index, entity, transform);
        }
    }
}

到了这里,关于【Unity】万人同屏, 从入门到放弃之——Entities 1.0.16性能测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 性能测试从入门到放弃(一)

    性能测试是观察系统在给定的运行环境下,测试场景中系统的性能表现是否符与预期目标一致,评判是否存在性能缺陷,根据结果识别性能瓶颈。 运行环境:硬件服务器、操作系统、网络、数据库、web服务器、应用服务器等都为系统的运行环境。 测试场景:用户如何使用系统

    2023年04月09日
    浏览(34)
  • 深聊性能测试,从入门到放弃之: Windows系统性能监控(三)任务管理器介绍及使用。

    关于Windows系统性能监控的前两篇 《 Windows系统性能监控(一) 性能监视器介绍及使用 》 《 Windows系统性能监控(二) 资源监控器介绍及使用 》 私下里有很多同学反馈,说学到了很多, 其实,在平时,如果我们能把集成好的服务监控应用起来, 你会收到意想不到的惊喜, 毕竟,

    2024年02月03日
    浏览(26)
  • 深聊性能测试,从入门到放弃之: Windows系统性能监控(二) 资源监控器介绍及使用。

    小屌丝 :鱼哥,我看了你这篇《Windows系统性能监控(一) 性能监视器介绍及使用》,让我学到了好多知识。 小鱼 :嗯,我自己在写这篇文章的时候,也学到了好多。 小屌丝 :是吗,你不都是知道了,咋还又学到了好多; 小鱼 :这个很正常啊,你把你会的知识,重新以文字

    2024年01月25日
    浏览(42)
  • Nginx 入门指南:从入门到放弃(不是!)从零开始掌握高性能 Web 服务器

    Nginx 可以构建高性能、可靠的 Web 服务器。本文将带你了解 Nginx 的基本概念、安装方法以及常见配置,让你快速上手并搭建自己的 Web 服务器。 随着互联网的发展,构建稳定、高性能的 Web 服务器成为了许多开发者的重要需求。而在众多的服务器软件中, Nginx 以其出色的性能

    2024年04月15日
    浏览(50)
  • 【Unity】Entities 1.0 学习(二):调试工具

            在 Entites 1.0 ,Unity修改了之前的调试面板,以及在场景下构建 Ecs World 的流程,较之前的版本差别还是蛮大的。         之前的学习大多集中在代码和语法,很多是对之前成熟的代码做升级改造,所以没有用到新的调试工具。但是最近在看 Unity 的新的 GameObject C

    2024年02月05日
    浏览(20)
  • 【Unity】Entities 1.0 学习(一):Aspect

            Unity在 2022年下半年(我印象是9月份左右)推出了 Entities 1.0 ,可以在 2022.2.0b8 以上的版本使用。当时我粗略地看了一下,但是没有深入学习。最近空闲时间稍多,就认真来学习一下 Entities 1.0有啥新的东西。         1.0 毕竟是大更新,改变的东西还是很多,所以应该

    2023年04月08日
    浏览(25)
  • Unity 多相机 同屏显示

    一 首先了解: 相机和Canvas 的渲染先后关系 什么是相机的 渲染顺序 ? 答:简单理解就是 用毛刷  刷墙面,先刷的,会被后刷的 挡住 。 列如:相机01: 先渲染的大海,相机02:后渲染的比基尼美女。那么呈现的效果就是:比基尼美女站在大海前面。 毛刷理解方式:一面空

    2024年02月16日
    浏览(24)
  • Unity 万人寻路(dots版本)

    时间:2023-7-29 北京下雨,公司停电,回家早了,更新一下。 寻路模块,还是前前后后,打磨了2个月,中间穿插着搞很多其他的功能,有些螺旋迭代的味道。 进入正题: 设计团队,会从游戏性角度考虑,提出很多需求。 1,单位之间的规避,模型不能穿插 2,建筑物规避,模

    2024年02月08日
    浏览(31)
  • 【Unity入门】16.脚本引用组件

          大家好,我是Lampard~~     欢迎来到Unity入门系列博客,所学知识来自B站阿发老师~感谢  (1)点击控制音频播放     还记得我们的车载音乐AudioSource吗?之前我们给小车加了这个组件使之在游戏运行的时候可以播放BGM     但是如果我们 不想一开始就播放,想在某个时

    2023年04月22日
    浏览(29)
  • Docker从入门到放弃

    看完我这里,就彻底入门了,如果对你有帮助,欢迎点赞+收藏❤️+评论噢~ 按部就班,先安装.. 在CentOS 7上安装Docker主要涉及添加Docker的官方仓库,然后从该仓库安装Docker CE(社区版) 1.安装所需的包: yum-utils 提供 yum-config-manager 工具,而 device-mapper-persistent-data 和 lvm2 是

    2024年04月14日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包