Contents

mesh ccd

mesh ccd

基本概念

false positives

a collision is reported when there is no collision

false negatives

a collision is not reported when there is a collision

Multivariate CCD Formulation

$$\begin{align*} &F_{\mathrm{vf}}(t, u, v)=p(t)-\left((1-u-v) v_1(t)+u v_2(t)+v v_3(t)\right)\\ &F_{\mathrm{vf}}: \Omega_{\mathrm{vf}}=[0,1] \times\{u, v \geqslant 0 \mid u+v \leqslant 1\} \rightarrow \mathbb{R}^3\\ &F_{\mathrm{ee}}(t, u, v)=\left((1-u) p_1(t)+u p_2(t)\right)-\left((1-v) p_3(t)+v p_4(t)\right)\\ &F_{\mathrm{ee}}: \Omega_{\mathrm{ee}}=[0,1] \times[0,1]^2 \rightarrow \mathbb{R}^3 \end{align*}$$

Univariate CCD Formulation

Normal Cone test

给定连续曲面S以及其边界C,若其不自交,则必须通过surface normal test和contour test

1.存在一个向量$\vec{v}$,使(N.v)> 0对曲面上的任意点都成立
2.轮廓C沿向量v的投影在投影平面上没有任何自交。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
struct cone
{
    Eigen::Vector3f axis;
    float angle;

    // input two axis and get the one axis
    void set(Eigen::Vector3f axis1, Eigen::Vector3f axis2)
    {
        axis = normalized(axis1 + axis2);
        angle = acos(axis1.dot(axis2)) * 0.5;
    }
};

Continus Normal Cone

./pic/1.png

$$\mathbf{n}_{\mathbf{t}}=\mathbf{n}_{\mathbf{0}} \cdot B_{0}^{2}(t)+\left(\mathbf{n}_{\mathbf{0}}+\mathbf{n}_{\mathbf{1}}-\delta\right) / 2 \cdot B_{1}^{2}(t)+\mathbf{n}_{\mathbf{1}} \cdot B_{2}^{2}(t)$$

基于伯恩斯坦基控制点的凸包性质,$\vec{n}_t$受到控制点的限制,控制点为$\mathbf{n_0}, \mathbf{n_1}, \mathbf{(n_0 + n_1 - \delta)/2}$

滤波器

代数非穿透滤波器(DNF)
可以剔除不满足共面条件的碰撞对

对于点面碰撞对,首先计算出三角形 ABC 的法线向量 n,然后计算四个点 PABC 在 n 上的投影点之间的距离,若距离为零,则 PABC 共面,否则不共面。

空间线性投影滤波器

可以剔除部分不满足内部条件的碰撞对

将空间中的碰撞对投影到空间中的某条直线上,根据投影点的位置关系来剔除不可能发生碰撞的碰撞对。 在点面碰撞中,若点的投影点始终在三角形3个顶点的投影点的同一侧,则可剔除;在边边碰撞中,若一条边的两个顶点的投影点始终在另一条边的两个顶点的投影点的同一侧,则可剔除。

基于深度神经网络优化的CCD算法剔除

CCD Root finding

三次多项式或多变量求根问题,如果floating-point rounding error无限小,理论上可以精确求解CCD问题

1.基于Inclusion的二分法求根

 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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// 基础的区间算法
// 代码源自CCD-Wrapper
namespace Eigen
{
typedef Matrix<intervalccd::Interval, Dynamic, 1, ColMajor, 3, 1> VectorX3I;    //定义一个行数可变,但是不大于3,列数固定为1的列向量
}


bool interval_root_finder(const std::function<Eigen::VectorX3I(const Eigen::VectorX3I&)>& f,
                       const std::function<bool(const Eigen::VectorX3I&)>& constraint_predicate,
                       const Eigen::VectorX3I& x0,
                       const Eigen::VectorX3d& tol,
                       Eigen::VectorX3I& x,const bool check_vf)
{
   std::stack<std::pair<Eigen::VectorX3I, int>> xs;
   xs.emplace_back(x0, -1);
   while(!xs.empty())
   {
       // copresond to line 6
       x = xs.top().first;
       int last_split = xs.top().second;
       xs.pop();

       // copresond to line 7
       // compute the inclusion function
       Eigen::VectorX3I y = f(x);

       if (!zero_in(y)) {
           continue;
       }

       Eigen::VectorX3d widths = width(x);
       if ((widths.array() <= tol.array()).all()) {
           if (constraint_predicate(x)) {
               return true;
           }
           continue;
       }

       // Bisect the next dimension that is greater than its tolerance
       int split_i;
       for (int i = 1; i <= x.size(); i++) {
           split_i = (last_split + i) % x.size();
           if (widths(split_i) > tol(split_i)) {
               break;
           }
       }

       std::pair<Interval, Interval> halves = bisect(x(split_i));
       Eigen::VectorX3I x1 = x;
       // Push the second half on first so it is examined after the first half
       if(check_vf){
           if(split_i==1){
               if(interval_satisfy_constrain(halves.second,x(2))){
                   x(split_i) = halves.second;
                   xs.emplace(x, split_i);
               }
               if(interval_satisfy_constrain(halves.first,x(2))){
                   x(split_i) = halves.first;
                   xs.emplace(x, split_i);
               }
           }
           if(split_i==2){
               if(interval_satisfy_constrain(halves.second,x(1))){
                   x(split_i) = halves.second;
                   xs.emplace(x, split_i);
               }
               if(interval_satisfy_constrain(halves.first,x(1))){
                   x(split_i) = halves.first;
                   xs.emplace(x, split_i);
               }
           }
           if(split_i==0){
               x(split_i) = halves.second;
               xs.emplace(x, split_i);
               x(split_i) = halves.first;
               xs.emplace(x, split_i);
           }
       }
       else{
           x(split_i) = halves.second;
           xs.emplace(x, split_i);
           x(split_i) = halves.first;
           xs.emplace(x, split_i);
       }
       
       
   }
   }
   return false
}

2.浮点数高精度运算
3.将数值问题转换为射线求交问题

大多数基于单变量公式的算法都会产生false negative

求解器优点缺点
interval root-finder (IRF)没有false negative,有少量的false positive,可以通过调整容差,通过准确性换取效率区间算法为计算提增加了性能开销,例如计算两个区间的乘积$[a,b] [c,d] = [min(ac,ad,bc,bd),max(ac,ad,bc,bd)]$,需要四次乘法和两次min max操作
univariate interval root-finder (UIRF) 刚体ccd的特殊情况如果多项式有无穷根,那么该算法将必须将整个域细化到最大允许分辨率,并检查每个区间的有效性,使其正确,但在退化情况下非常慢。这导致比多变量对应的平均运行时间更长。此外,也不可能控制其他两个参数(即u、v)的准确性,从而引入更多的假阳性。
floating-point time-of-impact root finder (FPRF)这种方法是速度最快的方法之一,是许多仿真代码中的主选。
TightCCD (TCCD)保守的基于浮点数的实现,速度快,唯一没有false negative的非区间方法产生了许多不可控制的false positive,这些false positive可能会导致不必要的碰撞检测,从而降低了整体性能。
Root Parity (RP)根据根的奇偶性来判断是否有碰撞,但是无法区分0根和重根
rational implementation of Root Parity (RRP)根据根的奇偶性来判断是否有碰撞,但是无法区分0根和重根
BSC
MSRF
Exact-Root-Parity-CCD基于RP方法,修复了其部分问题

./pic/ccd_compare.png

大多数使用单变量公式的算法都有false negative

Trajectories