💥 History-Based Collision
이전의 Level Set Based Collision을 보완한 충돌 처리 방법으로, 다음 위치를 충돌 법선 방향으로 투영하여 제한하던 이전 방법과는 다르게, 이는 원래의 속도를 그대로 투영하여 계산한다.
이는 다음 두 단계에 걸쳐 계산된다.
현재 위치 - 충돌 물체의 표면 - 다음 위치
🔎 충돌 감지 (Collision Detection)
앞에서 언급했듯이, 현재 속도를 법선 방향으로 투영하여 거리를 계산하는 이전 방법과는 다르게, 속도에 따른 다음 위치를 계산한 뒤, 이것과 표면으로부터의 수직 거리를 계산한다.
➡️ 이때, 계산한 거리 값이 음수라면 충돌을 의미한다.
📌 충돌 처리 (Collision Response)
충돌이 감지되면 다음과 같이 두 단계에 걸쳐 충돌 처리를 진행한다:
이때, $\theta$ 는 다음과 같이 표현된다:
이는 아래의 그림에서, 가중치를 나타내는 것을 확인할 수 있다:
따라서, 각 과정에선 다음과 같은 연산을 수행한다:
1. 첫 번째 과정 (현재 위치 - 충돌 물체의 표면)은 현재 속도에 현재 수직 거리만큼의 가중치를 주어 표면까지의 변위로 변환한다.
2. 두 번째 과정 (충돌 물체의 표면 - 다음 위치)은 속도에 남은 가중치인 (1- $\theta$)를 곱하여 변위를 계산한다. 이때, 두 번째 과정에서 사용되는 속도는 원래의 속도가 아닌, $\Gamma$ 함수를 적용하여 충돌 후의 마찰과 법선 방향 상대 속도를 제거한 속도 $v_{\star}$이다.
이때, $\Gamma$ 함수는 Level Set 기반 방법에서 계산하는 속도와 동일하며 식은 다음과 같다:
또한, $v_{\star}$ 는 아래와 같이 법선 방향 속도와 접선 방향 속도로 나누어 생각할 수 있다:
이때, 법선 방향 성분 $v_{\star N}$ 은 충돌 물체의 법선 방향 속도와 정점의 법선 방향 속도 중 더 큰 값을 선택하여 상대속도와 관련해서 더이상 가까워지지 않도록 계산한다:
접선 방향 성분 $v_{\star T}$ 은 마찰력을 고려하여, 두 번째 과정의 변위를 계산한다:
최종적으로 Level Set Based Collision 과 History-Based Collision 을 비교해보면 다음과 같다.
📌 충돌 처리 이후
추가적으로, 충돌 처리가 끝난 이후에 trapezoidal rule (사다리꼴 규칙)에서의 사용을 위해 앞에서 사용한 $\Gamma$ 함수를 사용해 새로운 속도 $v_{\star}$ 를 반환하며, 충돌 처리 도중에 적용되는 법선 방향의 힘은 모두 0이 되어야 한다.
법선 방향의 힘을 제거하여 힘을 적용하는 과정은 다음과 같다:
이때, $F_i$ 는 속도와 독립적인 힘이고 $F_d$는 속도에 선형 의존하는 감쇠 힘이다. 또한 $P$는 법선 방향의 힘을 제거하며, 다음과 같은 행렬 계산을 이용한다:
이는 힘에 의해 계산된 속도를 법선 방향으로 투영하여 원래의 속도에서 빼주는 과정을 거친다.
💻 구현 (Implement)
정점의 외부 힘에 의한 위치 계산은 이전에 다뤘던 PBD 방법으로 구현하였으며, 마지막에 속도를 다음과 같은 함수를 추가하여 구현하였다.
void PBD_PlaneCloth::HistoryBasedCollision(void) //평면은 정지 상태
{
double deltaT = 0.01f;
double h = 0.1f;
double coefficientFriction = 0.6f; //마찰 계수
for (int i = 0; i < _res[0]; i++) { //width
for (int j = 0; j < _res[1]; j++) { //height 모든 정점에 대하여 실행
int index = j * _res[0] + i;
double x = _pos[index].x();
double y = _pos[index].y();
double z = _pos[index].z();
vec3 N(PlaneCalPI(x + h, y, z) - PlaneCalPI(x, y, z),
PlaneCalPI(x, y + h, z) - PlaneCalPI(x, y, z),
PlaneCalPI(x, y, z + h) - PlaneCalPI(x, y, z));
N /= h; //법선 벡터 계산 (오일러 방법 이용) = Gradient PI
N.normalize();
double PI = PlaneCalPI(x, y, z); //PI, newPI 계산
vec3 newPos = _pos[index] + (_vel[index] * deltaT);
double newPI = PlaneCalPI(newPos);
if (newPI < 0)
{
double weight = PlaneCalPI(_pos[index]) / (PlaneCalPI(_pos[index]) - PlaneCalPI(newPos));
vec3 beforeV = _vel[index] * weight; //현재 위치 ~ 접촉면까지의 속도 (v~n+1/2)
vec3 xc = _pos[index] + beforeV * deltaT;
_vel[index] = beforeV; //업데이트
_pos[index] = xc;
// V star n+1/2 계산
double vpN = _vel[index].dot(N); //원래의 법선 방향 속력
vec3 vpNN = N * vpN; //원래의 법선 방향 속도
vec3 vpT = _vel[index] - vpNN; //원래의 접선 방향 속도
double newVpN = max(vpN, 0); //새로운 법선 방향 속력 (평면 속도 = 0 정지)
vec3 newVpNN = N * newVpN; // 새로운 법선 방향 속도
double friction = (coefficientFriction * (newVpN - vpN) / vpT.getNorm()); //마찰 계산
vec3 newVpT = vpT * (1 - friction);
if (1 - friction < 0)
newVpT.set(0, 0, 0);
vec3 Vnew = newVpNN + newVpT;
vec3 afterV = Vnew * (1 - weight);
_vel[index] = afterV; //업데이트
//_pos[index] = xc + afterV * deltaT;
}
}
}
}
double PBD_PlaneCloth::PlaneCalPI(double x0, double y0, double z0)
{
//ax + by + cz + d = 0 평면 방정식
double a = 0;
double b = 2;
double c = 3;
double d = 1;
return (a * x0 + b * y0 + c * z0 + d) / sqrt(pow(a, 2) + pow(b, 2) + pow(c, 2));
}
double PBD_PlaneCloth::PlaneCalPI(vec3 v)
{
//ax + by + cz + d = 0 평면 방정식
double a = 0;
double b = 2;
double c = 3;
double d = 1;
return (a * v.x() + b * v.y() + c * v.z() + d) / sqrt(pow(a, 2) + pow(b, 2) + pow(c, 2));
}
이는 위에서 설명했던 과정을 단순히 코드로 구현한 것으로, 중간의 첫 번째 과정의 위치 및 속도를 업데이트 하는 과정을 거쳤으며, 최종적으로 두 번째 단계의 속도를 업데이트 해주었다. 결과는 다음과 같다.
Level Set Based 방법과 History-Based 방법을 비교했다.
History Based Collision 방식이 좀 더 자연스러운 움직임을 보이는 것을 확인할 수 있다.
참고 자료 :
깃허브:
https://github.com/qkrdmstn/pbd-cloth-simulation.git
GitHub - qkrdmstn/pbd-cloth-simulation
Contribute to qkrdmstn/pbd-cloth-simulation development by creating an account on GitHub.
github.com
'물리 기반 시뮬레이션 > Cloth Simulation' 카테고리의 다른 글
[ Cloth Simulation & Collision ] 06. SDF 생성 (0) | 2025.05.15 |
---|---|
[ Cloth Simulation & Collision ] 05. Local Optimization for SDF (0) | 2024.01.17 |
[ Cloth Simulation & Collision ] 04. 천 자가 충돌 (Cloth Self-Collision) (0) | 2023.09.06 |
[ Cloth Simulation & Collision ] 02. 레벨 셋 충돌 (Level Set Collision) (0) | 2023.07.13 |
[ Cloth Simulation & Collision ] 01. 천 시뮬레이션 (Cloth Simulation) (0) | 2023.07.06 |