[ Cloth Simulation & Collision ] 04. 천 자가 충돌 (Cloth Self-Collision)

2023. 9. 6. 19:29·물리 기반 시뮬레이션/Cloth Simulation

👕 Cloth Self-Collision

하나의 천에서 서로 겹치거나, 부딪힐 때 면을 통과하지 않도록 하는 충돌 처리 방법이다.

❗ Self Collision이 적용되지 않은 천에서는 서로 부딪혔을 때 통과하는 등의 현상이 발생할 수 있다.

➡️ 따라서, 사실적인 천을 시뮬레이션 하기 위해서는 이러한 SelfCollision이 필요하다.

 

이러한 Self Collision은 다음과 같이 다섯 가지 방법을 통해 구현된다.

1. hash를 이용한 각 정점 접근

2. 떨림 현상을 피하기 위한 rest distance 사용

3. Iterator Solver와 CCD가 아닌 Sub-Stepping 사용

4. 최대 속도 제한

5. 안정적인 천-천 마찰 사용


🔴 Particle Hash

무작위로 배치된 정점들 사이에서, 일정 거리 내에 있는 정점(이웃한 정점)을 찾기 위해 Hashing을 사용한다.

➡️ 만약, 아래와 같이 이중 반복문을 이용해 모든 정점을 순회한다면 시간 복잡도가 $O(n^2)$ 이 된다. 이는 비효율적이다.

 

아래와 같이 그리드를 이용해 각 정점을 cell에 포함시키고, 인접한 cell에 포함된 정점만을 조사한다면 일정 거리 내에 있는 정점들을 찾을 수 있다.

➡️ 2차원 공간이라면 9칸, 3차원 공간이라면 27칸을 순회한다.

 

그리드 배열 형태로 각 파티클들을 저장하는 방법은 다음과 같다:

그리드 한 칸의 길이를 spacing이라 하면, 각 정점 위치를 이용하여 배열의 index를 계산할 수 있다. 이를 이용해 각 배열 index에 해당 정점의 index를 대입한다.


🔎 Dense Grid Representation

더 밀도 있는 배열을 만들기 위해 다음과 같이 각 cell에 포함된 정점의 수를 누적하여 배열을 만들고 정점이 모여 있는 파티클 배열을 추가한다.

➡️ 이때, 그리드 배열의 원소는 해당 cell의 첫 번째 입자가 파티클 배열의 어느 위치에 있는지를 나타낸다.


🔎 Handle Unbounded Grid With Hashing

✅ 시뮬레이션에 경계 그리드가 포함되지 않은 경우에는 Spatial Hashing 기법을 사용한다. 이는 정점의 위치 값을 정보로 hash 함수를 통해 index를 얻은 뒤, 이를 배열에 할당하는 방식이다.

 

➡️ 이때, 아래의 보라색과 파란색 cell처럼 다른 위치(cell)가 같은 index 값을 반환하는 Hash Collision이 발생할 수 있다. 하지만, Cloth Simulation에서는 cell에 포함된 입자들의 최소 거리 값을 계산하는 과정을 거치기 때문에 Hash Collision을 무시해도 무관하다.

 

❗ 그럼에도 거리 계산을 최소화하기 위해 hash function은 최대한 cell을 균등하게 분포시키도록 값을 반환해야 한다.

 

최종적인 Hash Table을 구성하는 과정은 다음과 같다.


📏 Rest Distance

아래의 그림과 같이 충돌 처리를 위한 거리(2r)와 거리 제약 조건의 거리가 중첩되면 떨림 현상이 발생한다.

➡️ 이를 방지하기 위해 충돌 거리를 설정한 충돌 거리와 거리 제약 조건의 잔여 거리 중 더 작은 것으로 선택한다.


🚶 Sub-Step

정점 간의 충돌을 놓치지 않기 위해 CCD(Continuous Collision Detection)나 Iterator Solver에 의한 반복 연산이 아닌, Sub-Step 방식을 사용한다.

 

알고리즘은 다음과 같다:

➡️ 이는 다음에 설명할 최대 속도를 제한하는 것과 관련이 있으며, 앞서 설명한 hash를 Sub-Step 과정 전에 한 번만 생성한다.

 

추가적으로, Iterator Solver에 의한 투영과 Sub-step 방식의 차이를 간단하게 살펴보면 다음과 같다:


⛔ Enforce Maximal Velocity

정점의 속도가 너무 빠를 경우, Sub-Step 과정에서 충돌을 놓칠 가능성이 있다.

➡️ 따라서, 다음 식을 통해 한 번의 서브 스텝 도중 최대 정점의 반지름 r만큼 즉, spatial hashing의 grid size 만큼만 이동할 수 있도록 속도를 제한한다:


👌 Stable Cloth-Cloth Friction

더욱 안정적인 천과 천 사이의 마찰을 계산하기 위해 다음과 같이 평균 속도를 사용하여 마찰력을 계산한다.


💻 Implement

Class Hash :

앞에서 설명한 Particle Hash를 구현한 Class로, 자세한 수치와 같은 코드는 생략했다.

class Hash
{
public:
	double spacing;
	int tableSize;
	int querySize;
	int numParticles;

	vector<int> cellStart; //cell Index 스타트 배열
	vector<int> cellEntries; //파티클 배열
	vector<int> queryIds; //인접 정점 배열
	vector<int> firstAdjId; //queryAll 함수의 스타트 배열 (Dense Grid Representation)
	vector<int> adjIds; //queryAll 함수의 인접 정점 배열
    
public:
	Hash();
	Hash(double _spacing, int _numParticles, int _numOfTri);
	~Hash();

public:
	int intCoord(double coord); //좌표 값을 int 값(내림)으로 반환
	int hashCoords(int xi, int yi, int zi); //hash function
	int hashPos(vec3 pos); //정점의 위치를 입력 받아 hash index로 변환
	void create(vector<vec3> _pos); // table 생성
	void query(vector<vec3> _pos, int index, double maxDist); //하나의 정점에 대해 주변 9칸 순회
	void queryAll(vector<vec3> _pos, double maxDist); //모든 정점에 대해 주변 9칸 순회
};

 

updatePPSelfCollision() :

void PBD_PlaneCloth::updatePPSelfCollision(double dt)
{
	double thickness2 = thickness * thickness;

	for (int i = 0; i < _res[0]; i++) { //width
		for (int j = 0; j < _res[1]; j++) { //height 모든 정점에 대하여 실행
			int index = j * _res[0] + i;

			int id0 = index;
			int first = _hash->firstAdjId[index];
			int last = _hash->firstAdjId[index + 1];
			
			for (int j = first; j < last; j++)
			{
				int id1 = _hash->adjIds[j];

				vec3 diffPos = (_pos1[id1] - _pos1[id0]);
				double dist2 = diffPos.lengthSquared();
				
				if (dist2 > thickness2 || dist2 == 0) //거리가 두께보다 멀면 처리 X
					continue;

				//rest distance
				double restDist2 = (_restPos[id1] - _restPos[id0]).lengthSquared();
				double minDist = thickness; //restDistance 와 thickness 중 작은 값을 minDist로 설정
				if (dist2 > restDist2)
					continue;
				if (restDist2 < thickness2)
					minDist = sqrt(restDist2);

				//position correction
				double dist = sqrt(dist2);
				diffPos = diffPos * ((minDist - dist) / dist);

				_pos1[id0] += diffPos * -0.5 ;
				_pos1[id1] += diffPos * 0.5 ;

				//friction
				vec3 v0 = (_pos1[id0] - _pos[id0]);
				vec3 v1 = (_pos1[id1] - _pos[id1]);

				vec3 Vavg = (v0 + v1) * 0.5;

				double damping = 0.3;
				_pos1[id0] = _pos1[id0] + (Vavg - v0) * damping ;
				_pos1[id1] = _pos1[id1] + (Vavg - v1) * damping;
			}
		}
	}	
}

앞서 설명한 과정을 그대로 모든 정점에 대해 실행하였다.

 


📈 Result

결과는 아래와 같이 Self-Collision을 적용한 것과 하지 않은 것을 비교해 보았다.

Self-Collision X
Self-Collision O

천이 겹치지 않고 잘 충돌하는 것을 확인할 수 있다.


참고 자료 : 

https://matthias-research.github.io/pages/tenMinutePhysics/index.html, (09 - Getting ready to simulate the world with XPBD, 11 - Finding overlaps among thousands of objects blazing fast, 15 - Self-collisions, solving the hardest problem in animation)


깃허브:

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 ] 03. 충돌 (History-Based Collisions)  (0) 2023.07.19
[ Cloth Simulation & Collision ] 02. 레벨 셋 충돌 (Level Set Collision)  (0) 2023.07.13
[ Cloth Simulation & Collision ] 01. 천 시뮬레이션 (Cloth Simulation)  (0) 2023.07.06
'물리 기반 시뮬레이션/Cloth Simulation' 카테고리의 다른 글
  • [ Cloth Simulation & Collision ] 06. SDF 생성
  • [ Cloth Simulation & Collision ] 05. Local Optimization for SDF
  • [ Cloth Simulation & Collision ] 03. 충돌 (History-Based Collisions)
  • [ Cloth Simulation & Collision ] 02. 레벨 셋 충돌 (Level Set Collision)
coding-l7
coding-l7
  • coding-l7
    coding-l7rl0
    coding-l7
  • 글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 기타
      • 유니티
        • OfficeWorkerRunning
      • 프로그래밍 언어
        • C
        • C#
        • C++
      • CS
        • 컴퓨터 구조
        • 운영체제
      • 물리 기반 시뮬레이션
        • 기초
        • Cloth Simulation
        • Fluid Simulation
      • 코딩 테스트
        • 프로그래머스
        • 백준
      • 독서
        • [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ]
        • [ 혼자 공부하는 컴퓨터 구조 + 운영체제 ]
        • [ CUDA 기반 GPU 병렬 처리 프로그래밍 ]
      • 영어
        • Basic Grammar In Use
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
    • 포트폴리오
  • 공지사항

  • 인기 글

  • 태그

    jump table
    bilateral blur
    유체 시뮬레이션
    wave simulation
    정수 승격
    collision
    Flip
    narrow range filter screen-space fluid rendering
    C언어
    OpenGL
    cloth simulation
    실수
    시스템 프로그래밍
    screen space fluid rendering
    명령어
    파동 난류
    fluid simulation
    물리 기반 시뮬레이션
    fluid implicit particle
    컴퓨터 구조
    상수
    GLSL
    position based dynamics
    입자 기반 방법
    RAM
    pbd
    surface turbulence
    screen-space rendering
    액체 시뮬레이션
    그리드 기반 방법
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
coding-l7
[ Cloth Simulation & Collision ] 04. 천 자가 충돌 (Cloth Self-Collision)
글쓰기
상단으로

티스토리툴바