Unity DOTS技术浅析

Unity DOTS

初识DOTS

Unity的Dots技术最近是很热的,我也在闲暇之余简单学习了一下,学习新的技术会让人快乐是件不争的事实对吧(努力安慰自己……)
Data-Oriented Technology Stack,这是它的全称,翻译过来叫多线程式数据导向型技术堆栈,这个是官方的翻译,多么的高大上,它首先给我带来的感觉就是一种新的编程思想,那就是面向数据,对于习惯了面向对象编程的我们Unity从业者来讲,接受它可能挺不适应的,至少在我最近的学习感受是这样。

UnityDOTS三大杀器:ECS,JobSystem&&BurstCompiler

ECS

ecs,即Entity,Component和System ,Entity它代表的就是一个实例,一个承载关联数据和行为的实体,就好比是一张身份证ID,有了它,对于一个人来说,它的行为,信息我们可以通过检索轻松拿到,Component承载的是数据,System承载的就是行为方法。这样的架构使得数据和行为解耦,提高了代码的扩展性

JobSystem

JobSystem是Unity退出的自己的多线程管理机制,它充分解放了计算机多核多线程的运算力,能为代码的执行速度带来不小的提升,而且用户不用处理繁琐的线程管理事务,十分的方便~关于JobSystem

BurstCompiler

Unity 构建了名为 Burst 的代码生成器和编译器,它有更高的效率。

应用实例

ECS

以官方的小球旋转为例,首先要做的就是构建Component数据类型,本利很简单,数据只有旋转速度,Component代码如下:
using System.Collections;
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;

public struct RotationSpeedComponent : IComponentData
{
    public float Speed;

}

注意:ECS中的Component数据必须是实现IComponentData的结构体,为什么要是结构体不是类呢?因为struct直接在栈里分配,它不像class一样分配在托管堆里,不进行垃圾回收,实现“连续紧凑的内存布局”,相比于数据分布在内存的各个角落的class,效率也会更高~
然后是System:

using System.Collections;
using System.Collections.Generic;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using Unity.Transforms;


public class RotationSpeedSystem : ComponentSystem
{

    protected override void OnUpdate()
    {
        Entities.ForEach((ref RotationSpeedComponent rotationSpeedComponent, ref Unity.Transforms.Rotation translation) =>
            {

                translation.Value = math.mul(math.normalize(translation.Value),quaternion.AxisAngle(math.up(), rotationSpeedComponent.Speed*Time.deltaTime));

            });
    }
}

Unity.Mathematics是UnityECS中新写的数学类,也是提高性能的举措之一,例子中的RotationSpeedSystem 继承自 ComponentSystem,它实现OnUpdate方法,这相当于我们熟悉的MonoBehavior的Update方法,实现每帧刷新的逻辑。
本例中Entity的构建要借助于Unity.Entities中的ConvertToEntity脚本,还要实现IConvertGameObjectToEntity接口,在方法中关联Component和System,将GameObject转化为Entity,代码如下:

using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;

public class EntitiesManager : MonoBehaviour,IConvertGameObjectToEntity
{

    public float speed=3;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void Convert(Entity entity, EntityManager entityManager, GameObjectConversionSystem conversionSystem)
    {
        var moveComponent=new RotationSpeedComponent(){Speed = speed};
        entityManager.AddComponentData(entity, moveComponent);
    }
}

这个脚本EntitiesManager 挂在GameObject身上,注意还要添加ConvertToEntity脚本~

在这里插入图片描述
这样就简单实现了一个ECS结构,当然用官方的话,这是混合ECS的写法,它与MonoBehaviour还是有一些瓜葛~
ECS也在不断迭代更新中,最新的版本,我们可以利用[GenerateAuthoringComponent]这个属性标签对Component声明,来省去EntitiesManager 脚本中关联Component和System的操作,使得代码更简洁~

ECS结合JobSystem的使用

还是物体旋转,如果我们需要数以万计的物体旋转,是可以用JobSystem实现多线程并行处理来,官方给出的ECS结合JobSystem的使用案例:
首先Component还是一样,这次用上面提到的[GenerateAuthoringComponent]属性标签来简化代码:

using System;
using Unity.Entities;

// ReSharper disable once InconsistentNaming
[GenerateAuthoringComponent]
public struct RotationSpeed_ForEach : IComponentData
{
    public float RadiansPerSecond;
}

在System中我们用 Entities.WithName方法来找到我们要处理的Component,并用ForEach处理每个的旋转行为,代码:

using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

// This system updates all entities in the scene with both a RotationSpeed_ForEach and Rotation component.

// ReSharper disable once InconsistentNaming
public class RotationSpeedSystem_ForEach : SystemBase
{
    // OnUpdate runs on the main thread.
    protected override void OnUpdate()
    {
        float deltaTime = Time.DeltaTime;
        
        // Schedule job to rotate around up vector
        Entities
            .WithName("RotationSpeedSystem_ForEach")
            .ForEach((ref Rotation rotation, in RotationSpeed_ForEach rotationSpeed) =>
            {
                rotation.Value = math.mul(
                    math.normalize(rotation.Value), 
                    quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * deltaTime));
            })
            .ScheduleParallel();
    }
}

ScheduleParallel方法其实就是运用了JobSystem的Schedule方法来实现对多个物体旋转的并行处理。

RotationSpeed_ForEach .cs要挂在我们的预制体上,可以看到,标签自动使得脚本变成RotationSpeed_ForEach Authoring,其实框架系统自动实现了与RotationSpeedSystem_ForEach的关联
在这里插入图片描述
然后是生成一万个预制物体的代码:

using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

// ReSharper disable once InconsistentNaming
[AddComponentMenu("DOTS Samples/SpawnFromMonoBehaviour/Spawner")]
public class Spawner_FromMonoBehaviour : MonoBehaviour
{
    public GameObject Prefab;
    public int CountX = 100;
    public int CountY = 100;

    void Start()
    {
        // Create entity prefab from the game object hierarchy once
        var settings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, null);
        var prefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(Prefab, settings);
        var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

        for (var x = 0; x < CountX; x++)
        {
            for (var y = 0; y < CountY; y++)
            {
                // Efficiently instantiate a bunch of entities from the already converted entity prefab
                var instance = entityManager.Instantiate(prefab);

                // Place the instantiated entity in a grid with some noise
                var position = transform.TransformPoint(new float3(x * 1.3F, noise.cnoise(new float2(x, y) * 0.21F) * 2, y * 1.3F));
                entityManager.SetComponentData(instance, new Translation {Value = position});
            }
        }
    }
}

Entity.Instantiate()是实例外化一个Entity的API。SetComponentData讲每个实例加入EntityManager中。
我们运行下,可以看到,它的FPS还是挺高的,性能很棒~
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200302103525263.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE5NzE0NDA3,size_16,color_FFFFFF,t_70

下面是用传统的GameObject.Instantiate方法复制预制体并在MonoBehaviour. Update方法中处理旋转的方法,它的性能比起ECS+Jobsystem差了不止一星半点。。
在这里插入图片描述
以上就是对ECS 官方案例的学习解读,可能有很多不足之处,望指正~ 附官方案例源码UnityECSSamples

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Unity DOTS(DOTS: Data-Oriented Technology Stack)是Unity的一种数据导向技术堆栈,它旨在提高游戏性能和可扩展性。它基于实体组件系统(Entity-Component-System,ECS)的概念,其中游戏对象被拆分为实体(Entity)和组件(Component),并通过系统(System)进行处理。 在Unity DOTS中,可以使用实体组件系统来管理和处理游戏对象。通过将游戏对象转换为实体和组件的形式,可以实现高效的数据处理和并行计算。例如,在创建实体时,可以使用GameObjectConversionUtility.ConvertGameObjectHierarchy函数将GameObject转换为Entity,并使用IConvertGameObjectToEntity接口进行自定义转换。然后,可以使用系统(System)对实体和组件进行处理,例如旋转方块事件。 Unity DOTS的优势包括更高的性能,更好的可扩展性和更方便的并行计算。通过采用数据导向的设计,可以减少内存访问和数据处理的开销,从而提高游戏的帧率和响应性。 总而言之,Unity DOTS是一种数据导向的技术堆栈,通过实体组件系统和并行计算来提高游戏性能和可扩展性。它可以通过转换游戏对象为实体和组件的形式,并使用系统进行处理来实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [UnityDots技术入门](https://blog.csdn.net/m0_37920739/article/details/108181541)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Unity DOTS简明教程](https://blog.csdn.net/mango9126/article/details/105219215)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值