案例三:使用Entity小球模拟数量级雨滴效果(Scne4)
本案例将结合上篇动态创建小球和第二篇学的ComponentSystem(组件系统)来模拟雨滴产生和下落过程,首先雨滴下落逻辑图:
脚本:DropData
using UnityEngine;
using Unity.Entities;
using Unity.Mathematics;
[System.Serializable]
public struct DropData : IComponentData
{
public float delay;
public float velocity;
}
脚本:Pure_DropMain
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Collections;
using Unity.Rendering;
using Unity.Transforms;
public class Pure_DropMain : MonoBehaviour
{
public int entityCount = 1000;
public int entityRange = 100;
public int delaySpeed = 1;
public int dropSpeed = 1;
public Mesh mymesh;
public Material mymaterial;
void Start()
{
this.CreatePureMain();
}
void CreatePureMain()
{
#region 1.创建本地实体数组
// 世界自动创建的唯一实体管理器
EntityManager entityManager = World.Active.EntityManager;
// 创建一个原型模型(可以类比 GameObject.CreatePrimitive ), 函数参数代表该实体有哪些组件(注意要想实体在场景中显示必须有 Translation,RenderMesh,LoalToWorld这三个组件)
EntityArchetype entityArchetype = entityManager.CreateArchetype
(
typeof(Translation),
typeof(RenderMesh),
ComponentType.ReadWrite<LocalToWorld>(), // 实体的矩阵,
ComponentType.ReadOnly<DropData>() //
);
NativeArray<Entity> entities = new NativeArray<Entity>(entityCount, Allocator.Temp);
entityManager.CreateEntity(entityArchetype, entities);
#endregion
#region 2.初始化数组中的实体数据
for (int i = 0; i < entityCount; i++)
{
// 初始化位置信息
Translation translation = new Translation();
translation.Value = Random.insideUnitSphere * entityRange; // 设置位置为随机的球体
translation.Value.y = 0;
entityManager.SetComponentData<Translation>(entities[i], translation); // 设置位置信息
// 初始化延迟时间
entityManager.SetComponentData<DropData>(entities[i], new DropData { delay = Random.Range(1, 10), velocity = Random.Range(1, 100) });
// 给所有实体 设置网格 和材质 信息 这些UnityECS做了优化处理,使用共享网格材质的函数进行添加
entityManager.SetSharedComponentData<RenderMesh>(entities[i], new RenderMesh { mesh = mymesh, material = mymaterial });
}
entities.Dispose(); // 这里把内存缓冲区释放掉
#endregion
}
}
脚本: DropSystem
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Transforms;
public class DropSystem : ComponentSystem
{
public float minHeight = -100; // 下落最低值
protected override void OnUpdate()
{
// 通过ECS提供的筛方式遍历场景中包含该数据组件的实体
Entities.ForEach((ref Translation translation, ref DropData dropData) =>
{
if (dropData.delay > 0)
{
dropData.delay -= Time.deltaTime;
}
else
{
if (translation.Value.y < minHeight)
{
translation.Value.y = 0;
dropData.velocity = Random.Range(1, 10);
dropData.delay = Random.Range(1,10);
}
else
{
translation.Value.y -= dropData.velocity * Time.deltaTime;
}
}
});
}
}
如上图,脚本部署完毕,创建一个空物体将,Pure_DropMain挂在空物体上然后设置好初始值等运行。我初始化了10万个小球,当生成数量级实体的时候,对于网格啊或者材质我们可以用到GPU加速的技术来提高游戏性能。
如下图开启了材质 enable GPU insatncing 功能,GPU的使用率会提高到 100%,另外我这种用法只做参考,还在学习中。
想了解原理,具体详情参考:
Unity的性能优化CPU/GPU/内存:https://blog.csdn.net/brucethl/article/details/82147758
Unity中使用GPU Instancing优化SkinnedMesh渲染:https://blog.csdn.net/xoyojank/article/details/80980629
Unity GPU Instancing: https://www.xuanyusong.com/archives/4640
远程仓库(github):https://github.com/h1031464180/UnityECS