Games 103 cloth PDB 浅析
简介
PDB 比 隐式积分法 速度快很多.
全称 Position Based Dynamics 粒子动力学系统, 什么是PBD呢? 个人的理解就是, 多次迭代, 达到一步的稳定状态. 然后更新整个系统的状态. 简单的说, 就是对于局部的模拟扩展到全局. 经过一定的迭代, 达到稳态.
可以参看Image中的第一幅图片. 对于单个系统的更新, 导致的全局的收敛. 但是必须达到多次迭代, 才能达到类似整体的一次迭代.
参考文献
师弟代码~~
Q&A
Q1
In the Update function, set up the PBD solver as a particle system. Specifically, for every vertex, damp the velocity (as in 1.a), update the velocity by gravity, and finally
update the position:
简单而言就是, 改变速度. 通过重力改变, 然后加上速度衰减, 然后根据速度的改变更新坐标.
V[i] += g * t;
V[i] *= damping;
X[i] += t * V[i];
Q2
1.b. Strain limiting (4 Points) In the Strain Limiting function, implement position-based
dynamics in a Jacobi fashion. The basic idea is to define two temporary arrays sum x[] and sum n[]
to store the sums of vertex position updates and vertex count updates. At the beginning of the
function, set both arrays to zeros. After that, for every edge e connecting i and j, update the arrays:
Finally, update each vertex as:
\[\mathbf{v}_{i} \leftarrow \mathbf{v}_{i}+\frac{1}{\Delta t}\left(\frac{0.2 \mathbf{x}_{i}+s u m_{-} \mathbf{x}_{i}}{0.2+s u m_{-} n_{i}}-\mathbf{x}_{i}\right), \quad \mathbf{x}_{i} \leftarrow \frac{0.2 \mathbf{x}_{i}+s u m_{-} \mathbf{x}_{i}}{0.2+\operatorname{sum_n} n_{i}} \]作者给出的 \(\alpha = 0.2f\) 可以参考最后一张图.
void Strain_Limiting()
{
Mesh mesh = GetComponent ().mesh;
Vector3[] vertices = mesh.vertices;
//Apply PBD here.
Vector3[] sum_x = new Vector3[vertices.Length];
int[] num_x = new int[vertices.Length];
for(int i=0; i
image
code
using UnityEngine;
using System.Collections;
public class PBD_model: MonoBehaviour {
float t= 0.0333f;
float damping= 0.99f;
int[] E;
float[] L;
Vector3[] V;
Vector3 g = new Vector3(0, -9.8f, 0);
float r = 2.7f;
// Use this for initialization
void Start ()
{
Mesh mesh = GetComponent ().mesh;
//Resize the mesh.
int n=21;
Vector3[] X = new Vector3[n*n];
Vector2[] UV = new Vector2[n*n];
int[] T = new int[(n-1)*(n-1)*6];
for(int j=0; j _E[i + 1])
Swap(ref _E[i], ref _E[i+1]);
//Sort the original edge list using quicksort
Quick_Sort (ref _E, 0, _E.Length/2-1);
int e_number = 0;
for (int i=0; i<_E.Length; i+=2)
if (i == 0 || _E [i + 0] != _E [i - 2] || _E [i + 1] != _E [i - 1])
e_number++;
E = new int[e_number * 2];
for (int i=0, e=0; i<_E.Length; i+=2)
if (i == 0 || _E [i + 0] != _E [i - 2] || _E [i + 1] != _E [i - 1])
{
E[e*2+0]=_E [i + 0];
E[e*2+1]=_E [i + 1];
e++;
}
L = new float[E.Length/2];
for (int e=0; epivot_0 || a[j*2]==pivot_0 && a[j*2+1]> pivot_1);
if(i>=j) break;
Swap(ref a[i*2], ref a[j*2]);
Swap(ref a[i*2+1], ref a[j*2+1]);
}
Swap (ref a [l * 2 + 0], ref a [j * 2 + 0]);
Swap (ref a [l * 2 + 1], ref a [j * 2 + 1]);
return j;
}
void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
void Strain_Limiting()
{
Mesh mesh = GetComponent ().mesh;
Vector3[] vertices = mesh.vertices;
//Apply PBD here.
Vector3[] sum_x = new Vector3[vertices.Length];
int[] num_x = new int[vertices.Length];
for(int i=0; i ().mesh;
Vector3[] X = mesh.vertices;
//For every vertex, detect collision and apply impulse if needed.
GameObject sphere = GameObject.Find("Sphere");
Vector3 c = sphere.transform.position;
//Handle colllision.
for (int i = 0; i < X.Length; i++)
{
if (i == 0 || i == 20) continue;
float distance = (X[i] - c).magnitude;
if (distance < r)
{
V[i] += (c + r * (X[i] - c) / distance - X[i]) / t;
X[i] = c + r * (X[i] - c) / distance;
}
}
mesh.vertices = X;
}
// Update is called once per frame
void Update ()
{
Mesh mesh = GetComponent ().mesh;
Vector3[] X = mesh.vertices;
for(int i=0; i