补全Start函数中的部分
inv_Dm = new Matrix4x4[tet_number];
for(int i = 0; i < tet_number; i++)
{
Matrix4x4 Dm = Build_Edge_Matrix(i);
inv_Dm[i] = Dm.inverse;
}Build_Edge_Matrix函数
Matrix4x4 Build_Edge_Matrix(int tet)
{
Matrix4x4 ret=Matrix4x4.zero;
//TODO: Need to build edge matrix here.
for (int i = 0; i < 3; i++)//使用 tet 四面体的顶点坐标构建边矩阵。矩阵的前三列存储了三个边向量,这些向量是从四面体的第一个顶点到其他三个顶点的向量
{
ret[0, i] = X[Tet[tet * 4 + i + 1]].x - X[Tet[tet * 4 + 0]].x;
ret[1, i] = X[Tet[tet * 4 + i + 1]].y - X[Tet[tet * 4 + 0]].y;
ret[2, i] = X[Tet[tet * 4 + i + 1]].z - X[Tet[tet * 4 + 0]].z;
}
ret[3, 3] = 1.0f;//ret[3, 3] = 1.0f 用于将矩阵转换为齐次坐标
return ret;
}
_Update函数
// Jump up.
if(Input.GetKeyDown(KeyCode.Space))
{
for(int i=0; i<number; i++)
V[i].y+=0.2f;
}
for(int i=0 ;i<number; i++)
{
//TODO: Add gravity to Force.
Force[i] = mass * new Vector3(0, -9.8f, 0);
}
for(int tet=0; tet<tet_number; tet++)
{
Matrix4x4 F = Build_Edge_Matrix(tet) * inv_Dm[tet];
//TODO: Green Strain
Matrix4x4 G = Matrix4x4_mul_float(Matrix4x4_minus_Matrix4x4(F.transpose * F, Matrix4x4.identity), 0.5f);
//TODO: Second PK Stress
Matrix4x4 S = Matrix4x4.zero;
float trace = G[0, 0] + G[1, 1] + G[2, 2];
S = Matrix4x4_add_Matrix4x4(Matrix4x4_mul_float(G, 2.0f * stiffness_1), Matrix4x4_mul_float(Matrix4x4.identity, stiffness_0 * trace));
//TODO: Elastic Force
float volume = 1.0f / (inv_Dm[tet].determinant * 6);
Matrix4x4 Elastic_force = Matrix4x4_mul_float(F * S * inv_Dm[tet].transpose, -volume);
for (int k = 0; k < 3; k++)//将弹性力应用到顶点
{
Force[Tet[tet * 4 + k + 1]].x += Elastic_force[0, k];
Force[Tet[tet * 4 + k + 1]].y += Elastic_force[1, k];
Force[Tet[tet * 4 + k + 1]].z += Elastic_force[2, k];
}
// Elastic_force0 = -Elastic_force1-Elastic_force2-Elastic_force3
//将弹性力添加到四面体的顶点上。前三个顶点的力加上 Elastic_force,第一个顶点的力减去所有其他顶点的力,以保证力的平衡
Force[Tet[tet * 4 + 0]].x -= Elastic_force[0, 0] + Elastic_force[0, 1] + Elastic_force[0, 2];
Force[Tet[tet * 4 + 0]].y -= Elastic_force[1, 0] + Elastic_force[1, 1] + Elastic_force[1, 2];
Force[Tet[tet * 4 + 0]].z -= Elastic_force[2, 0] + Elastic_force[2, 1] + Elastic_force[2, 2];
}
Smooth_V(0.75f);
for(int i=0; i<number; i++)
{
//TODO: Update X and V here.
V[i] = (V[i] + dt * Force[i] / mass) * damp;//Force[i] / mass 计算每个顶点所受的加速度,dt * Force[i] / mass 计算时间步长 dt 内的速度变化量
X[i] = X[i] + V[i] * dt;//X[i] + V[i] * dt 使用更新后的速度计算新位置
//TODO: (Particle) collision with floor.处理与地面的碰撞
float d = Vector3.Dot(X[i] - P, N);//计算顶点与地面的距离 Vector3.Dot(X[i] - P, N) 计算顶点到地面某一点的向量在地面法线 N 上的投影,得到顶点到地面的垂直距离 d
if (d < 0.0f) // collision occur
{
//计算法向速度分量 v_N_size
float v_N_size = Vector3.Dot(V[i], N);//Vector3.Dot(V[i], N) 计算速度 V[i] 在法线方向上的分量 v_N_size
// check velocity检查法向速度方向
if (v_N_size < 0.0f)//v_N_size < 0.0f,表示顶点在向下运动,需要处理碰撞
{
Vector3 v_N = v_N_size * N;//Vector3 v_N = v_N_size * N 计算法向速度分量 v_N
Vector3 v_T = V[i] - v_N;//Vector3 v_T = V[i] - v_N 计算切向速度分量 v_T
Vector3 v_N_new = -1.0f * 0.5f * v_N;//Vector3 v_N_new = -1.0f * restitution * v_N 计算碰撞后的法向速度,应用恢复系数 restitution 进行反弹
float a = Math.Max(1.0f - 0.5f * (1.0f + 0.5f) * v_N.magnitude / v_T.magnitude, 0.0f);//计算切向速度的衰减系数,考虑摩擦系数 friction 和恢复系数 restitution
Vector3 v_T_new = a * v_T;//计算碰撞后的切向速度
V[i] = v_N_new + v_T_new;//更新顶点速度,包含新的法向速度和切向速度
}
}
}