在程序化建模中,有向距离场Signed Distance Field (SDF) 因其优雅的数学性质非常适合用于网格的动态生成。最近我的个人项目在做一个基于SDF的体素建造系统,实现SDF物理碰撞检测后,发现在物体破坏时会出现空气墙的情况。
通常SDF中有两种常用的操作,并(min)和交(max),用于实现物体的添加和删除。但是并和交操作会破环有向距离场的定义,使用并交合成后的结果并不是精确的距离场。
float opSubtraction( float d1, float d2 ) { return max(-d1,d2); } float opUnion( float d1, float d2 ) { return min(d1,d2); }
如下图所示
- A点位于正方形外,距离正方形最近的角(表面)距离为 0.6
- A点位于圆形外,距离圆表面的距离为 0.1,取反后为 -0.1
- 应用公式:
从算法可得,挖完洞后,A点离新形状的表面距离依然是 0.6,但是正方形原本的“角”已经不存在了,A点距离“新表面”(那个被挖出的圆弧凹面)的真实几何距离,肉眼可见地大于 0.6。如绿色线表示
通过min,max组合结果通常并不是该形状真实的距离场,而只是距离的一种下界(lower bound)。
这样会导致什么问题?
- 基于sdf进行raymarch就会导致步长过小,收敛变慢。
- 基于sdf做碰撞检测,会出现空气墙的情况
比如还是上图的情况,有一个半径为0.6的圆正在移动,此时在A点进行采样,得出最近表面距离是0.6,使用SDF做碰撞检测,得出此时已经碰撞到物体表面。停止移动。但实际上这里是空的,仍然可以向前移动。
因此使用max只能保证了形状边界是正确的,但失去了外部距离场的准确性。
使用min会失去形状内部距离场的准确性。
最后并没有找到好的解决办法,老老实实用网格做碰撞检测吧。
