Unity3D 进阶教程 - 19 高级物理与自定义碰撞

概述

入门系列第 07-08 篇介绍了 PhysX 引擎的基础——Rigidbody、Collider、碰撞事件。当游戏需要 非标准碰撞形状自定义物理材质大规模碰撞检测、或 超越 PhysX 的功能 时,内置物理引擎就不够了。

本篇覆盖:物理查询高级用法、CCD(连续碰撞检测)、Physics Scene、以及用 Job System 实现自定义物理。

1. 物理查询进阶

1.1 批量查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AdvancedPhysicsQuery : MonoBehaviour
{
private readonly RaycastHit[] _results = new RaycastHit[32];
private readonly Collider[] _overlapResults = new Collider[32];

private int BatchRaycast(Vector3 origin, Vector3 direction, float distance)
{
return Physics.RaycastNonAlloc(origin, direction, _results, distance);
}

private int OverlapSphere(Vector3 center, float radius)
{
var layerMask = LayerMask.GetMask("Enemy", "Obstacle");
return Physics.OverlapSphereNonAlloc(center, radius, _overlapResults, layerMask);
}
}

1.2 使用 LayerMask 过滤

1
2
3
4
5
6
7
8
9
10
public class LayerMaskFilter : MonoBehaviour
{
public void FilteredQuery()
{
var playerMask = LayerMask.GetMask("Player");
var playerAndEnemy = LayerMask.GetMask("Player", "Enemy");

Physics.Raycast(transform.position, transform.forward, out var hit, 100f, playerAndEnemy);
}
}

2. CCD(连续碰撞检测)

默认 PhysX 使用离散碰撞检测——物体移动过快时会穿透薄物体。CCD 解决这个问题:

1
2
3
4
5
6
7
8
9
public class CCDSetup : MonoBehaviour
{
private void Start()
{
var rb = GetComponent<Rigidbody>();

rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
}
}
CCD 模式 性能开销 防穿透效果
Discrete 最低 高速穿透
Continuous 中等 对静态物体有效
Continuous Dynamic 最高 所有物体

3. 自定义物理场景

3.1 独立物理场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CustomPhysicsScene : MonoBehaviour
{
private PhysicsScene _physicsScene;

private void Start()
{
var parameters = new CreateSceneParameters(LocalPhysicsMode.Physics3D);
var scene = SceneManager.CreateScene("PhysicsScene", parameters);
_physicsScene = scene.GetPhysicsScene();
}

private void FixedUpdate()
{
if (_physicsScene.IsValid())
_physicsScene.Simulate(Time.fixedDeltaTime);
}
}

3.2 手动控制模拟

1
2
3
4
5
6
7
8
9
10
11
12
public class ManualPhysics : MonoBehaviour
{
private void Start()
{
Physics.autoSimulation = false;
}

private void Update()
{
Physics.Simulate(Time.fixedDeltaTime);
}
}

4. Job System 自定义物理

当 Unity 物理引擎成为瓶颈时,用 Job System 实现轻量级自定义物理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[BurstCompile]
public struct CustomPhysicsJob : IJobParallelFor
{
public NativeArray<float3> positions;
public NativeArray<float3> velocities;
public NativeArray<float> radii;
public float deltaTime;
public float3 gravity;

public void Execute(int index)
{
velocities[index] += gravity * deltaTime;
positions[index] += velocities[index] * deltaTime;

// 地面碰撞
if (positions[index].y < 0)
{
positions[index].y = 0;
velocities[index].y = -velocities[index].y * 0.5f;
}
}
}

4.1 球体碰撞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[BurstCompile]
public struct SphereCollisionJob : IJobParallelFor
{
public NativeArray<float3> positions;
public NativeArray<float3> velocities;
[ReadOnly] public NativeArray<float> radii;

public void Execute(int index)
{
var pos = positions[index];
var vel = velocities[index];
var rad = radii[index];

for (int j = index + 1; j < positions.Length; j++)
{
var delta = positions[j] - pos;
var dist = math.length(delta);

if (dist < rad + radii[j])
{
var normal = delta / dist;
var overlap = (rad + radii[j]) - dist;

positions[index] -= normal * overlap * 0.5f;
positions[j] += normal * overlap * 0.5f;

var relVel = velocities[j] - vel;
var velAlongNormal = math.dot(relVel, normal);
if (velAlongNormal > 0) continue;

var impulse = normal * velAlongNormal;
velocities[index] += impulse;
velocities[j] -= impulse;
}
}
}
}

5. 物理稳定性提升

1
2
3
4
5
6
7
8
9
10
public class PhysicsStability : MonoBehaviour
{
private void Awake()
{
Physics.defaultSolverIterations = 10;
Physics.defaultSolverVelocityIterations = 4;
Physics.defaultMaxAngularSpeed = 50f;
Physics.defaultContactOffset = 0.01f;
}
}

总结

  • 物理查询:批量 NonAlloc 版本避免 GC,LayerMask 精确过滤
  • CCD:高速物体开启 Continuous 防穿透
  • 自定义物理场景:隔离物理计算
  • Job System 物理:简单碰撞可以完全绕过 PhysX 自己实现
  • 空间分区:Grid / QuadTree / Octree 减少 O(n^2) 碰撞对

下一篇是最后一篇 完整项目框架搭建,综合运用本系列所有知识构建可扩展的游戏架构。

ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
分享: