물리 기반 시뮬레이션/Cloth Simulation

[ Cloth Simulation & Collision ] 03. 충돌 (History-Based Collisions)

coding-l7 2023. 7. 19. 20:30

💥 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 Collision

 

History-Based Collision

Level Set Based 방법과 History-Based 방법을 비교했다.

History Based Collision 방식이 좀 더 자연스러운 움직임을 보이는 것을 확인할 수 있다.


참고 자료 :

Robust High-Resolution Cloth Using Parallelism, History-Based Collisions and Accurate Friction - Andrew Selle, Jonathan Su, Geoffrey Irving, Ronald Fedkiw


깃허브:

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