|
|
- Vector3 oDisplacement = refPos - refPosPrevious;
- Vector3 displacement = oDisplacement;
- std::vector< Vector3, AlignedAllocator<Vector3> > normal_list;
- _CollisionDetectionStaticSceneOctreeNode(_StaticSceneOctreeRoot.get(), object, mat, aabb, normal_list);
- int sizeNormal = (int)normal_list.size();
- float lenDisp = displacement.Mod();
- for (int idx = 0; idx < sizeNormal; ++idx)
- {
- Vector3& n = normal_list[idx];
- float dotProduct = displacement * n;
- if (dotProduct < 0)
- {
- Vector3 v = dotProduct * n;
- displacement -= v;
- }
- }
- for (int idx = 0; idx < sizeNormal - 1; ++idx)
- {
- const Vector3& n0 = normal_list[idx];
- for (int idx_ = idx + 1; idx_ < sizeNormal; ++idx_)
- {
- const Vector3& n1 = normal_list[idx_];
- if (n0 * n1 < 0)
- {
- Vector3 n = n0.CrossProduct(n1).Normalize();
- float dotProduct = displacement * (n0 + n1).Normalize();
- if (dotProduct < 0)
- displacement = displacement * n * n;
- }
- }
- }
- correctional = displacement - oDisplacement;
复制代码
这段代码从我的静态场景的碰撞检测函数 CollisionDetectionStaticScene 中摘录。这反映了一个困扰我多日的主要问题。
首先,关于碰撞检测,我通过消除碰撞多边形面法线上的投影来修正运动向量。而当发生碰撞的若干多边形存在相交面夹角或其负角为锐角的情况,两次投影的结果仍会在某一多边形面法线方向包含位移分量。
为了消除这一位移,我首先考虑了多次迭代以尽可能消除影响,且当修正后的运动位移足够小时设置为 0,但这并不能阻止当存在:夹角角度过低,有限的迭代次数并不能有效消除投影;运动位移在锐角面无关的分量上含有不可忽略的偏移值,使得经过有限次迭代,修正的运动位移仍不接近于 0,故而在锐角面的合并阻力方向上仍存在少量位移并导致错误产生。并且,多次迭代的方式复杂且低效,以及以上若干原因,并不总是能正确工作。
经过不懈的努力,通过在消除投影阶段,查找存在的锐角面(相应的两多边形的法线夹角或其负角为钝角),计算两个面法线的垂直向量作为运动位移向量的投影法线,以垂直法线的平均法线和运动位移的方向关系是远离或者靠近来决定是否对运动位移进行投影,使得运动位移不趋近锐角面的任一平面。
通过以上修改,执行效果相当理想,因为不确定大家是否使用类似的思路或者遭遇过类似的问题以至另有可优化的空间,所以把这个问题整理出来。时间关系,并未附图说明。 |
|