후우.. mesh attach로 구현하면 될 줄 알았더니 큰 오해였다.
결국 vertex 두 개 사이에 constaint를 적용하는 방법을 알아보는 게 좋을 것 같다.
constraint
현재 구현된 시뮬레이션 물리엔진에서는 constraint가 4 가지가 있다.
그 중 isometric bending constraint는 현재 사용되지 않는다.
vertex끼리 끌어당기기 위해 중요한 것은 distance constraint일 것이다.
특히 그 중에서도 초기 particle과 particle 사이의 distance를 결정짓는 부분이 있을 것이고,
vertex를 완전히 붙이려면 이 distance를 지정한 vertex 끼리만 0으로 세팅하면 될 것이다.
하나 더 생각이 나는데, 보통 constraint를 설정하면 모든 particle에 solve 되는 것이 기본이다.
그렇다면 constraint가 특정 particle에만 적용되도록 하려면 어떻게 해야할까?
constraint는 solve 함수에서 각 particle들에 대해 프로세스를 수행하게 되고
constraint별 solve는 physics object의 solve 함수에서 순회하면서 실행한다.
즉 어떤 두 vertex 사이에서 constraint를 특별히 다르게 처리하고 싶다면
결국 solve 함수의 매개변수로 해당 vertex index를 넘겨준 뒤, constraint의 solve가 넘겨받은 vertex index에 대해서만 따로 처리해주는 방법이어야한다.
edge vertex index
코드를 좀 보니까 초기 거리 설정에 대한 것은 solve가 아니라,
생성자에서 initialize edge lengths가 있었다.
vertex index 1와 index 2가 있으면 이 두 vertex를 잇는 edge의 id를 찾아서 거기에 적용하는것이 이론상 가능하다.
그럼 edge id가 어떤 vertex 두 개의 사이에 있는 edge인지 어떻게 알 수 있을까?
get edge ids를 보면 id0, id1이 edge ids에 들어가는데, 정확히는 edge 에 대한 id가 아니라
edge를 구성하는 vertex의 id였다. 그리고 세 vertex가 이루는 한 삼각형에 대해서 각각의 edge를 이루는 vertex 한 쌍을 id0, id1에 넣고 edge로 반영한다.
이때 중복되는 edge가 들어가지 않도록 한다.
그렇다면 중복되지 않은 edge의 양쪽 vertex가 edgeIds에는 (2n, 2n+1)의 쌍으로 들어가있다는 말이 되며,
두 개의 attach할 vertex를 찾으면 이 edgeIds에서 index값이 일치하는 것을 찾으면 된다는 말이다.
initialize edge lengths
여기서 id0와 id1의 초기 거리를 edgeLengths에 저장하게 된다.
그렇다는 것은 이 부분에서 edgeLengths를 0으로 저장하게 되면, 두 정점이 딱 달라붙도록 시뮬레이션할 수 있다는 말이 된다.
궁금해서 이렇게 초기거리를 모두 0으로 설정해보았다.
시뮬레이션을 하면 이렇게 확 뭉쳐져 버린다.
양쪽으로 벌어진 것은 아무래도 빨래집게처럼 고정한 정점이 있기 때문이다.
초기거리를 특정값으로 조정해버리면 이렇게 불규칙한 주름이 생겨버린다.
원래 모델에서 vertex끼리 유지하던 거리보다 가까운 거리를 강제적으로 설정하면 이렇게 규칙적? 인 것 처럼 주름이 생기게 된다.
옷의 주름이 생기는 원리와 비슷할까 싶다.
테스트 용도로 index 0과 index 1번 vertex의 거리를 0으로 설정해보았다.
시뮬레이션이 시작하자, 0번 1번이 위치한 가장자리 부분이 꼬여버린다.
attach id list 전달하기
이제 vertex 두 개를 지정하면 constraint에서 index id를 찾아 처리할 수 있도록 initialize edge length 함수로 전달하는 방법에 대해서 구현해보자.
일단 constraint의 생성자가 실행되는 순간 초기 거리가 지정되므로, vertex 두 개를 연결한 정보 리스트를 시뮬레이션 start 시점에서 한 번에 보내주어야한다.
// Calculate and initialize rest lengths of distance constraints
private initializeEdgeLengths(attachIdList: [number,number][]) {
for (let i = 0; i < this.edgeLengths.length; i++) {
const id0 = this.edgeIds[2 * i];
const id1 = this.edgeIds[2 * i + 1];
this.edgeLengths[i] = Math.sqrt(
vecDistSquared(this.positions, id0, this.positions, id1)
);
attachIdList.forEach(ids=>{
if(id0 === ids[0] && id1 === ids[1] ||
id0 === ids[1] && id1 === ids[0]){
this.edgeLengths[i] = 0;
}
})
}
}
attach id list라는 튜플 형태로 전달하고 foreach를 도는 형태로 구현해보자.
새로운 mode를 attach vertex라고 하고, 기존에 구현했던 방식은 face를 끌어당겨 붙이는 느낌이므로 expand vertex라고 바꾸자.