Unity DOTS物理引擎的核心分析与详解
最近DOTS发布了正式的版本,同时基于DOTS的理念实现了一套高性能的物理引擎,今天我们来给大家分享和介绍一下这个物理引擎的使用。
Unity.Physics的设计哲学
Unity.Physics是基于DOTS设计思想的一个高性能C#物理引擎的实现, 包含了物理刚体的迭代计算与碰撞检测等查询。Unity.Physics的设计理念与PhyX和Havok有所不同,它们追求的是全特性的物理模拟,而Unity.Physics追求的是最常用的一些物理机制的实现,相比传统的物理引擎,它实现的是物理引擎的核心子集,这样导致比传统的物理引擎实现起来更简单与高效,同时能满足大部分的需求。
对惹,这里有一个游戏开发交流小组,大家可以点击进来一起交流一下开发经验呀!
传统的物理引擎在迭代计算的时候为了保证物理引擎计算结果的稳定性,缓存了很多的状态,这样就给整个系统设计增加了复杂度与开销。比如传统物理引擎还考虑到了网络游戏的情况下,你整个物理引擎的回滚与向前迭代计算。Unity.Physics就丢弃掉了这些,使得更容易控制和更高效。Unity.Physics物理引擎的迭代与计算都是基于Job与ECS机制的,由于没有cache计算中的物理状态,导致它的性能会比传统的物理引擎在某些方面性能要好。Unity.Physics的里面的物理参数与数据描述与传统的Havok物理引擎兼容,这样如果我们的项目中要追求物理引擎的全面性与稳定性,我们可以很容易的使用Havok等商业的物理引擎。在Unity DOTS里面,如果你获得了物理引擎Havok的授权,你可以直接在Unity DOTS中使用Havok物理引擎。
Unity.Physics的源码目录结构如下:
- Base: 包含了Unity.Pysics物理引擎使用的基本数据容器与数学计算;
- Collistion: 包含了所有的碰撞检测与空间检测的算法代码;
- DFG:包含了DataFlowGraph数据,在碰撞世界里面执行碰撞与设想检测;
- Dynamics:包含了所有的物理引擎的运动计算,约束计算,迭代计算;
- ECS: 包含了将ECS的组件数据导入,导出到Unity.Physics引擎中;
- Extensions: 包含了一些工具性质的代码,扩展的一些组件,调试工具等;
Unity.Physics的物理引擎的全局设置
要对Unity DOTS的物理引擎做全局设置,我们可以给DOTS里面的SubScene添加一个”PhysicsStep”的组件实例。如下图所示:
- Simulation Type: 下拉选项包含Unity Physics, Havok Physics, None,你可以来选择物理引擎的内核,如果你获得了Havok的商业授权,你就可以看到Havok Physics的选项。
- Gravity: 设置整个物理世界的张力加速度;
- Solver Iteration Count: 设置每次迭代计算的次数,次数越大,计算结果越精确稳定,但是也消耗更多的性能;
- Multi Threaded: 是否基于多线程来进行迭代物理计算,如果勾选上,物理引擎会使用较多的线程来进行迭代计算,否则就使用少量的线程来迭代计算。
Unity DOTS 物理引擎简单的案例
接下来利用Unity DOTS来实现一个简单的物理引擎的案例,编写一个脚本TargetAuthoring.cs, 代码如下:
using Unity.Entities;
using UnityEngine;
public struct Target : IComponentData
{
public Entity TargetEntity;
public float MaxDistance;
}
public class TargetAuthoring : MonoBehaviour
{
public GameObject TargetGameObject;
public float MaxDistance;
}
public class TargetAuthoringBaker : Baker<TargetAuthoring>
{
public override void Bake(TargetAuthoring authoring)
{
var component = new Target
{
MaxDistance = authoring.MaxDistance,
TargetEntity = GetEntity(authoring.TargetGameObject)
};
AddComponent(component);
}
}
再新建一个MovingBodyAuthoring.cs的文件,代码如下:
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Transforms;
using UnityEngine;
public struct MovingBody : IComponentData
{
public float Velocity;
}
public class MovingBodyAuthoring : MonoBehaviour
{
public float Velocity;
}
class MovingBodyAuthoringBaker : Baker<MovingBodyAuthoring>
{
public override void Bake(MovingBodyAuthoring authoring)
{
var component = new MovingBody
{
Velocity = authoring.Velocity
};
AddComponent(component);
}
}
public partial struct MovingBodySystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
foreach (var(target, transform, moving, velocity) in SystemAPI.Query<RefRO<Target>, RefRO<LocalTransform>, RefRW<MovingBody>, RefRW<PhysicsVelocity>>().WithAll<MovingBody>())
{
var targetPosition = SystemAPI.GetComponent<LocalTransform>(target.ValueRO.TargetEntity).Position;
var direction = math.normalize(targetPosition - transform.ValueRO.Position);
if (math.distance(targetPosition, transform.ValueRO.Position) < target.ValueRO.MaxDistance)
velocity.ValueRW.Linear = moving.ValueRO.Velocity * direction;
else
velocity.ValueRW.Linear = new float3(0, 0, 0);
}
}
}
打开SubScene场景,创作3个物体,一个地面(Cube),一个球体(Sphere),一个立方体节点(Target)。在球体上挂TargetAuthoring与MoveBodyAuthoring两个组件,并设置MoveBodyAuthoring的Velocity与MaxDistance为1与5,设置TargetAuthoring组件的的TargetGameObject为Target节点对象。
运行,效果如下: