PBD(Position Based Dynamics)学习笔记

符号说明

仿真物体包括 N N N 个节点和 M M M 个约束。

每个节点 i ∈ [ 1 , . . . , N ] i\in [1,...,N] i[1,...,N] 包含的参数有质量 m i m_i mi 、位置 x i \boldsymbol{x_i} xi 和速度 v i \boldsymbol{v_i} vi

每个约束 j ∈ [ 1 , . . . , M ] j\in[1,...,M] j[1,...,M] 包含的参数有:

  • 基数 n j n_j nj
  • 约束函数 C j : R 3 n j → R C_j: \mathbb{R}^{3n_j} \rightarrow \mathbb{R} Cj:R3njR
  • 节点编号集合 { i 1 , . . . , i n j } ,   i k ∈ [ 1 , . . . , N ] \{i_1,...,i_{n_j}\}, \ i_k\in[1,...,N] {i1,...,inj}, ik[1,...,N]
  • 刚度参数 k j ∈ [ 0 , 1 ] k_j\in[0,1] kj[0,1] ,描述约束的强度;
  • 约束类型:等式 或 不等式;
    • 等式表示 C j ( x i 1 , . . . , x i n j ) = 0 C_j(\boldsymbol{x_{i_1}},...,\boldsymbol{x_{i_{n_j}}})=0 Cj(xi1,...,xinj)=0
    • 不等式表示 C j ( x i 1 , . . . , x i n j ) ≥ 0 C_j(\boldsymbol{x_{i_1}},...,\boldsymbol{x_{i_{n_j}}})\ge 0 Cj(xi1,...,xinj)0

算法流程

首先初始化 x i = x i 0 \boldsymbol{x_i}=\boldsymbol{x_i^0} xi=xi0 v i = v i 0 \boldsymbol{v_i}=\boldsymbol{v_i^0} vi=vi0 ω i = 1 / m i \omega_i=1/m_i ωi=1/mi ,然后在每个 Δ t \Delta t Δt 时间内重复一次以下过程:

  1. 处理外力: v i ← v i + Δ t w i f e x t ( x i ) \boldsymbol{v_i} \leftarrow \boldsymbol{v_i} + \Delta t w_i f_{ext}(\boldsymbol{x_i}) vivi+Δtwifext(xi)
  2. 速度阻尼: d a m p V e l o c i t i e s ( v 1 , . . . , v N ) dampVelocities(\boldsymbol{v_1},...,\boldsymbol{v_N}) dampVelocities(v1,...,vN)
  3. 下一个位置预测: p i ← x i + Δ t v i \boldsymbol{p_i} \leftarrow \boldsymbol{x_i}+\Delta t \boldsymbol{v_i} pixi+Δtvi
  4. 碰撞检测,生成 M c o l l M_{coll} Mcoll 个碰撞约束: g e n e r a t e C o l l i s i o n C o n s t r a i n t s ( x i → p i ) generateCollisionConstraints(\boldsymbol{x_i}\rightarrow \boldsymbol{p_i}) generateCollisionConstraints(xipi)
  5. 若干次迭代:每次迭代处理一遍所有约束 p r o j e c t C o n s t r a i n t s ( C 1 , . . . , C M + M c o l l , p 1 , . . . , p N ) projectConstraints(C_1,...,C_{M+M_{coll}},\boldsymbol{p_1},...,\boldsymbol{p_N}) projectConstraints(C1,...,CM+Mcoll,p1,...,pN)
  6. 速度、位置更新: v i ← ( p i − x i ) / Δ t \boldsymbol{v_i}\leftarrow (\boldsymbol{p_i}-\boldsymbol{x_i})/\Delta t vi(pixi)/Δt x i ← p i \boldsymbol{x_i}\leftarrow \boldsymbol{p_i} xipi
  7. 碰撞节点的速度更新: v e l o c i t y U p d a t e ( v i , . . . , v N ) velocityUpdate(\boldsymbol{v_i},...,\boldsymbol{v_N}) velocityUpdate(vi,...,vN)

流程详细说明

2

由于物体内部的摩擦力、粘性等特性,节点速度变化时会有阻尼。PBD中速度阻尼的计算方法如下:

首先计算系统的质心、角速度:

  • 质心 x c = ( Σ i x i m i ) / ( Σ i m i ) \boldsymbol{x_c}=(\Sigma_i{\boldsymbol{x_i}m_i})/(\Sigma_i{m_i}) xc=(Σiximi)/(Σimi)
  • 质心速度 v c = ( Σ i v i m i ) / ( Σ i m i ) \boldsymbol{v_c}=(\Sigma_i{\boldsymbol{v_i}m_i})/(\Sigma_i{m_i}) vc=(Σivimi)/(Σimi)
  • 系统角动量 L = Σ i r i × ( m i v i ) \boldsymbol{L}=\Sigma_i{\boldsymbol{r_i}\times (m_i\boldsymbol{v_i})} L=Σiri×(mivi) ,其中 r i = x i − x c \boldsymbol{r_i}=\boldsymbol{x_i}-\boldsymbol{x_c} ri=xixc
  • 系统转动惯量 I = Σ i r i ~ r i ~ T m i \boldsymbol{I}=\Sigma_i{\widetilde{\boldsymbol{r_i}}\widetilde{\boldsymbol{r_i}}^Tm_i} I=Σiri ri Tmi
  • 系统角速度 ω = I − 1 L \boldsymbol{\omega}=\boldsymbol{I}^{-1}\boldsymbol{L} ω=I1L

然后设定一个全局的参数 k d a m p i n g ∈ [ 0 , 1 ] k_{damping}\in[0,1] kdamping[0,1] ,对于每个节点的速度 v i \boldsymbol{v_i} vi,做如下变换:

  1. Δ v i = v c + ω × r i − v i \Delta \boldsymbol{v_i}=\boldsymbol{v_c}+\boldsymbol{\omega}\times\boldsymbol{r_i}-\boldsymbol{v_i} Δvi=vc+ω×rivi
  2. v i ← v i + k d a m p i n g Δ v i \boldsymbol{v_i}\leftarrow\boldsymbol{v_i}+k_{damping}\Delta\boldsymbol{v_i} vivi+kdampingΔvi

从中可看出 k d a m p i n g k_{damping} kdamping 描述了阻尼强度,如果 k d a m p i n g = 1 k_{damping}=1 kdamping=1,那么系统为刚体;如果 k d a m p i n g = 0 k_{damping}=0 kdamping=0,那么每个节点自由运动,不存在阻尼。

4

当某个物体的一个节点从 x \boldsymbol{x} x 运动到 p \boldsymbol{p} p 时,可能与其它物体发生碰撞,这里碰撞有两种类型(原文描述的两种类型为 continuous collision 和 static collision,但我不明白这么命名的原因):

  • x \boldsymbol{x} x 在另一个物体外部而 p \boldsymbol{p} p 在另一个物体内部;
  • x \boldsymbol{x} x p \boldsymbol{p} p 都在另一个物体内部;

对于这两种类型,我们都希望 p p p 能够被约束到另一个物体外部,因此构造如下约束:

  • 对于第一种类型,构造不等式约束 C ( p ) = ( p − q c ) ⋅ n c C(\boldsymbol{p})=(\boldsymbol{p}-\boldsymbol{q_c})\cdot\boldsymbol{n_c} C(p)=(pqc)nc ,刚度参数 k = 1 k=1 k=1
  • 对于第二种类型,构造不等式约束 C ( p ) = ( p − q s ) ⋅ n s C(\boldsymbol{p})=(\boldsymbol{p}-\boldsymbol{q_s})\cdot\boldsymbol{n_s} C(p)=(pqs)ns ,刚度参数 k = 1 k=1 k=1

还有其它很多碰撞检测的约束方法,比如运动节点和运动三角形的。

5

这一步要迭代若干次,因为其本质是用了类似**牛顿迭代法(Newton’s Method / Newton-Raphson Method)**的方法。

牛顿迭代法,用于求解方程 f ( x ) = 0 f(x)=0 f(x)=0,迭代函数为 x k + 1 = x k − f ( x k ) f ′ ( x k ) x_{k+1}=x_k-\frac{f(x_k)}{f^{'}(x_k)} xk+1=xkf(xk)f(xk),迭代足够多次时 x x x 接近零点。

而每一次迭代,采取了 Gauss-Seidel method 的思想,即独立地一个个地处理每个约束(Gauss-Seidel method 在求解 A x = b Ax=b Ax=b 时,一个个地求取 x i x_i xi,并且当前求取的 x i x_i xi 会用到后面分量的求取中)。

因此,第5步的过程就是:循环若干次,每次循环时一个个处理所有约束。

约束有两类,一类是固有的 M M M 个约束,另一类是每次碰撞检测生成的 M c o l l M_{coll} Mcoll 个约束,前者需要满足动量和角动量守恒,而后者不用。由于 C ( p ) C(\boldsymbol{p}) C(p) 的值与刚体运动(平移、旋转)无关,也就是说刚体运动对应 p \boldsymbol{p} p 的变化位于 C ( p ) C(\boldsymbol{p}) C(p) 的等值线上,因此梯度 ∇ p C ( p ) \nabla_{\boldsymbol{p}}C(\boldsymbol{p}) pC(p) 与刚体运动正交,如果 p \boldsymbol{p} p 的变化 Δ p \Delta\boldsymbol{p} Δp 位于 ∇ p C ( p ) \nabla_{\boldsymbol{p}}C(\boldsymbol{p}) pC(p) 的方向上,那么自然能保持动量守恒(这里存疑……)。

假设所有节点质量相等,下面说明如何处理一个等式约束 C ( p ) = C ( p 1 , . . . , p n ) = 0 C(\boldsymbol{p})=C(\boldsymbol{p_1},...,\boldsymbol{p_n})=0 C(p)=C(p1,...,pn)=0

对于当前的 p \boldsymbol{p} p ,我们需要计算一个 Δ p \boldsymbol{\Delta p} Δp,使得 C ( p + Δ p ) ≈ C ( p ) + ∇ p C ( p ) ⋅ Δ p = 0 C(\boldsymbol{p}+\boldsymbol{\Delta p})\approx C(\boldsymbol{p})+\nabla_{\boldsymbol{p}}C(\boldsymbol{p})\cdot\boldsymbol{\Delta p}=0 C(p+Δp)C(p)+pC(p)Δp=0 ,由于 Δ p \Delta\boldsymbol{p} Δp 在梯度的方向上,因此可设 Δ p = λ ∇ p C ( p ) \Delta\boldsymbol{p}=\lambda\nabla_{\boldsymbol{p}}C(\boldsymbol{p}) Δp=λpC(p) ,联立求解可得
Δ p = − C ( p ) ∣ ∇ p C ( p ) ∣ 2 ∇ p C ( p ) (1) \Delta\boldsymbol{p}=-\frac{C(\boldsymbol{p})}{|\nabla_{\boldsymbol{p}}C(\boldsymbol{p})|^2}\nabla_{\boldsymbol{p}}C(\boldsymbol{p}) \tag{1} Δp=pC(p)2C(p)pC(p)(1)
上式就是牛顿迭代法中的一步变化 p ← p + Δ p \boldsymbol{p}\leftarrow\boldsymbol{p}+\Delta\boldsymbol{p} pp+Δp,而一次迭代需要对所有约束都作这样的计算。

我们将 Δ p \Delta\boldsymbol{p} Δp 进行拆分,可以得到与 (1) 等价的式子
Δ p i = − s ∇ p i C ( p ) (2) \Delta\boldsymbol{p}_i=-s\nabla_{\boldsymbol{p}_i}C(\boldsymbol{p}) \tag{2} Δpi=spiC(p)(2)
其中
s = C ( p ) ∣ ∇ p C ( p ) ∣ 2 = C ( p ) Σ j ∣ ∇ p j C ( p ) ∣ 2 (3) s=\frac{C(\boldsymbol{p})}{|\nabla_{\boldsymbol{p}}C(\boldsymbol{p})|^2} = \frac{C(\boldsymbol{p})}{\Sigma_j{|\nabla_{\boldsymbol{p}_j}C(\boldsymbol{p})|^2}} \tag{3} s=pC(p)2C(p)=ΣjpjC(p)2C(p)(3)
这么做是为了处理节点质量不相等的情况,当质量不相等时, p i \boldsymbol{p}_i pi 的变化应当与质量成反比。因此考虑质量的倒数 ω i = 1 / m i \omega_i=1/m_i ωi=1/mi ,可得
Δ p i = − s n ω i Σ j ω j ∇ p i C ( p ) (4) \Delta\boldsymbol{p}_i=-s\frac{n\omega_i}{\Sigma_j\omega_j}\nabla_{\boldsymbol{p}_i}C(\boldsymbol{p}) \tag{4} Δpi=sΣjωjnωipiC(p)(4)
对于不等式约束,我们只在 C ( p ) < 0 C(\boldsymbol{p})<0 C(p)<0 时进行迭代变换。

如果再考虑每个约束的刚度参数 k k k,假设需要 n s n_s ns 轮迭代(这里或许是:假设还需要 n s n_s ns 轮迭代?),我们将位置修正 Δ p \Delta\boldsymbol{p} Δp 乘上系数 1 − ( 1 − k ) 1 / n s 1-(1-k)^{1/n_s} 1(1k)1/ns ,存在线性误差 Δ p ( 1 − k ) \Delta\boldsymbol{p}(1-k) Δp(1k)

7

这一步是用来更新发生了碰撞的节点的速度的。

如果一个节点发生了碰撞,假设碰撞位置的法向量为 n \boldsymbol{n} n ,那么该节点速度垂直于 n \boldsymbol{n} n 的分量将因为摩擦力而减少,并且由于反弹会产生与 n \boldsymbol{n} n 同方向的速度分量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值