unity 下一帧执行_使用Unity的ECS和Job System实现流体模拟效果

Unity中实体组件系统ECS,Job System和Burst编译器,这些新工具的特点是让性能得到极高的提升。本文将由法国的开发工程师Léonardo Montes为我们分享如何将项目移植到ECS和Job system。当我在巴黎独立游戏工作室Atomic Raccoon工作时,我希望了解如何在运行时模拟多个角色像流体一样互相交互。Unity中实体组件系统ECS,Job System和...
摘要由CSDN通过智能技术生成

Unity中实体组件系统ECS,Job System和Burst编译器,这些新工具的特点是让性能得到极高的提升。本文将由法国的开发工程师Léonardo Montes为我们分享如何将项目移植到ECS和Job system。

当我在巴黎独立游戏工作室Atomic Raccoon工作时,我希望了解如何在运行时模拟多个角色像流体一样互相交互。

Unity中实体组件系统ECS,Job System和Burst编译器,这些新工具的特点是拥有极快的速度,而且性能提升效果高达100倍。于是我向团队建议使用这些新工具来实现流体模拟,这将允许我们通过制作小型物理引擎的原型来熟悉新的编码方式。

我首先研究可以尝试实现的物理模拟效果,然后找到了软粒子流体力学SPH算法。本文我将介绍如何在Unity实现SPH算法,以及如何将项目移植到ECS和Job system。

24e446fbb7b584987e008fa2a0bf6b8c.png

学习准备

本文提供项目的源代码下载:

https://github.com/leonardo-montes/Unity-ECS-Job-System-SPH

进行开发前,我仔细观察了Unity的Boid演示项目,该示例展示了很多条鱼相交互的效果。下面是Unite大会中关于ECS和Job System的演讲。

6012715a1abdcac243f81deea0b72a93.png

单线程实现

我使用“老方法”实现了SPH算法,也就是使用Monobehaviours。

首先,我调用InitSPH() 来创建粒子的游戏对象,并初始化它们的属性,并给位置和引用设置了正确参数,以便为模拟使用,这将让我得到一组粘性较大的粒子。

然后,我在每一帧调用ComputeDensityPressure()、ComputeForces()和Integrate(),它们会处理粒子与粒子间的碰撞。

我添加了二个方法:ComputeColliders()和ApplyPosition()。ComputeColliders()可以处理粒子与标记为“SPHCollider”的墙体游戏对象之间的碰撞,ApplyPosition()方法用于将粒子游戏对象的位置设为和粒子位置相同。

void Start()    

{    

   InitSPH();    

}    

void Update()    

{    

   ComputeDensityPressure();    

   ComputeForces();    

   Integrate();    

   ComputeColliders();    

   ApplyPosition();    

}    

这样就完成了,效果如下图所示。

a421005fc7b529e8c22b4cfc2ffcc2d8.gif

250个粒子

使用ECS和Job System实现

下面我们将使用ECS和Job System来实现流体模拟。

现在我们要改变思考方式,我们需要使用多个脚本,而不是只用一个脚本来初始化并更新粒子及其游戏对象。

初始化

首先,我将创建了一个SPHManager.cs脚本,它将处理新粒子和墙体的初始化过程。

void Start()

{

    //导入

    manager = World.Active.GetOrCreateManager();

    // 设置

    AddColliders();

    AddParticles(amount);

}

在单线程版本中,我可以将游戏对象定义为碰撞体,然后运行碰撞求解算法。但在这里,我需要将粒子转为由系统进行处理实体。

我将粒子加入到NativeArray中,然后使用一个游戏对象预制件来实例化实体,该预制件将用作每个实体使用的所有组件的模版。

基于被定义为碰撞体的游戏对象,循环处理了所有实体来设置数值。

void AddColliders()

{

    // 找到所有碰撞体

    GameObject[] colliders = GameObject.FindGameObjectsWithTag("SPHCollider");

    // 将它们转换为实体

    NativeArray entities = new NativeArray(colliders.Length, Allocator.Temp);

    manager.Instantiate(sphColliderPrefab, entities);

    // 设置数据

    for (int i = 0; i < colliders.Length; i++)

    {

        manager.SetComponentData(entities[i], new SPHCollider

        {

            position = colliders[i].transform.position,

            right = colliders[i].transform.right,

            up = colliders[i].transform.up,

            scale = new float2(colliders[i].transform.localScale.x / 2f, colliders[i].transform.localScale.y / 2f)

        });

    }

    //  完成

    entities.Dispose();

}

sphColliderPrefab由二个组件构成:GameObjectEntity 组件和SPHCollider组件。

5fabb3c62ae2362614a213094b11cd99.png

自定义组件保存了执行墙体碰撞后所需的数据,代码和单线程版本相同,只不过我使用了新的数学库和float3类型,而不是Vector3类型。ComponentDataWrapper部分允许组件在检视窗口添加给游戏对象。

using Unity.Entities;    

using Unity.Mathematics;    

[System.Serializable]    

public struct SPHCollider : IComponentData    

{    

  public float3 position;    

  public float3 right;    

  public float3 up;    

  public float2 scale;    

}    

public class SPHColliderComponent : ComponentDataWrapper { }    

现在对粒子做同样的处理,我循环处理了所有粒子来设置它们的位置。

void AddParticles(int _amount)
{
   NativeArray entities = new NativeArray(_amount, Allocator.Temp);
   manager.Instantiate(sphParticlePrefab, entities);
   for (int i = 0; i < _amo

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值