基于有向距离场(Signed Distance Field, SDF)的碰撞检测
项目简介
SDF 碰撞检测 Demo,演示如何使用有向距离场实现高效的角色碰撞检测和移动。包含 2D/3D 场景示例和可视化烘焙工具。
项目地址:SDFCollision
有向距离场
有向距离场(Signed Distance Field,简称 SDF)是一种描述空间中任意一点到某个几何形状最短距离的数学表示方法,通过符号指示点的位置:
| 符号 | 含义 |
|---|---|
| 正值 | 点在形状外部 |
| 负值 | 点在形状内部 |
| 零值 | 点位于形状边界上 |
SDF 通过将场景中每个点到障碍物表面的距离存储为标量值,可在 O(1)时间内查询碰撞,实现高效的碰撞检测。
快速使用
- 将
Assets目录下的文件导入到你的 Unity 工程中 - 打开
SDFDemo(3D)或SDFDemo2D(2D)场景 - 运行即可看到碰撞效果
SDF 烘焙
打开烘焙窗口
菜单栏选择 Tools > SDF Baker
参数说明
| 参数 | 说明 |
|---|---|
| 地图的长度/宽度 | 场景中烘焙区域的实际尺寸(米) |
| 每个分块的宽高 | 每个 SDF 数据块的物理尺寸(米) |
| 每个体素的大小 | 每个采样点的精度,越小精度越高 |
| 烘焙方向 | XY 或 XZ 平面,决定 2D 碰撞的平面方向 |
| 起始点 Transform | 拖入 Transform 自动计算烘焙原点 |
烘焙步骤
- 设置场景参数
- 拖入起始点 Transform(或手动设置起始位置)
- 选择保存路径(必须在
Assets/Resources/下) - 点击
Bake SDF开始烘焙
烘焙完成后会生成:
SDFConfig.json- 配置文件- SDF 数据文件(Texture2D 格式)
API 参考
SDFManager
碰撞管理器,挂载在场景中作为单例使用。
using SDFCollision;
获取距离
// 获取世界坐标到最近障碍物的距离
float distance = SDFManager.Instance.GetDistanceFromPoint(worldPosition);
// distance > 0 表示在障碍物外部
// distance < 0 表示在障碍物内部
// distance = 0 表示在障碍物表面
碰撞后滑行
// 检测碰撞并计算滑行方向(推荐用于角色移动)
// moveVec2: 移动向量
// position: 当前世界坐标
// radius: 角色半径
// buffer: 碰撞缓冲距离(适当增大可避免频繁反弹)
Vector2 newMoveDir = SDFManager.Instance.CheckAndCorrectMoveDir(
moveVec2,
position,
radius,
buffer: 0.1f
);
碰撞后反弹
// 检测碰撞并计算反射方向
Vector2 newMoveDir = SDFManager.Instance.CheckAndReflection(
moveVec2,
position,
radius
);
SDFConfig
烘焙配置类,存储烘焙参数和 SDF 数据路径。
// 通过路径加载配置
SDFConfig config = SDFConfig.LoadSDFConfig("SDFTextures");
// 字段说明
public int gridLength; // 网格长度(X 轴方向)
public int gridWidth; // 网格宽度
public int chunkSize; // 单个分块的分辨率
public float voxelSize; // 体素大小
public bool isXY; // 烘焙方向:true = XY, false = XZ
public Vector3Int startPos;// 烘焙起始点
public string sdfDataPath; // SDF 数据文件路径
核心概念
梯度与法线
在 SDF 碰撞检测中,梯度向量指向障碍物表面法线方向,用于计算碰撞后的滑行或反射方向。通过有限差分法计算:
gradient = (SDF(x+δ) - SDF(x-δ)) / 2δ
缓冲距离
buffer 参数控制碰撞缓冲区域大小:
- 值越小:碰撞响应越灵敏,但可能出现频繁弹跳
- 值越大:移动越平滑,但可能穿墙
