개발 · 컴퓨터공학/three.js / / 2024. 6. 19. 09:24

Threejs Cloth Tailor 개발일지 - 바닥 옮기기, 정점 고정 떼기, vertex debugger

728x90
반응형

 

바닥 옮기기

생각해보니까 이렇게 되는 현상부터 처리해야한다

시뮬레이션 constraint의 바닥부터 옮겨보자

 

physics-objects
solve(dt: number) {
    for (let i = 0; i < this.numParticles; i++) {
      // Floor collision ( we currently don't have a need for it)
      let y = this.positions[3 * i + 1];
      const height = -0.7;
      if (y < height) {
        vecCopy(this.positions, i, this.prevPositions, i);
        this.positions[3 * i + 1] = height;
      }
    }
    for (const constraint of this.constraints) {
      constraint.solve(dt);
    }

    for (const collision of this.collisions) {
      collision.solve(dt);
    }
  }

여기 solve 함수에서 height보다 y가 작으면 충돌하는 floor기능이 있다

오랜만에 봐서 헷갈리는데 3*i+1은 xyz중 각 파티클의 y좌표값이다

 

그럼 여기 들어가는 상수 height를 변수화 시켜서 각 씬에서 조절할 수 있도록 만들어보자

 

let height = -0.7

export function setFloorHeight(_height:number){
  height = _height
}

physics object의 height를 조절할 수 있는 함수를 export한다 

 

가만보니 physics object는 추상 클래스이므로 이를 상속받은 cloth 객체에서 함수를 실행할 수 있도록

export 방법이 아니라 그냥 함수로 만들자 

 

이거 기존 씬에도 바닥이 이미 있는데 이 위치를 floor에 해당하는 위치로 변경하면 

시각적으로 좋을 것 같다

 

시도해보니 아쉽게도 바닥의 position y좌표는 physics-object의 height같과 수치가 달랐다

같은 height 값을 사용할 수는 없어서 수치적 조정이 좀 필요할 듯 한데..

 

plane.position.setY(floorHeight * 0.3)

일단 0.3을 곱하니까 바닥으로 그럴듯하게 적용이 되는 것 같다 

 

근데 파티클의 y좌표가 왜 plane object의 y좌표와 비율이 다를까 싶어서

plane object를 world좌표계로 설정해보았는데 plane의 경우 scene 바로 밑에 있는 거라서 local과 world가 똑같다

 

다른 방법은 파티클의 경우 모델 하위에 있으므로 onepiece model의 local좌표에 영향을 받는게 아닐까 싶다

 

log를 찍어보면 파티클의 좌표가 시뮬레이션을 통해  -5 밑으로는 내려가지 않는다

 

근데 현재 

plane.position.setY(floorHeight * 0.3)

로 0.3배를 곱해서 그렇게 나온 것 같은데 흠..

 

이거 복잡한 옷 모델을 가지고는 파티클의 포지션을 분석하기 어려울 것 같다 

 

그래서 큐브로 바꿨는데, 왜 이렇게 휑 하게 밑에 칸만 떨어지냐

위의 네 개의 vertices가 고정된 이유는 무엇이고 왜 면끼리 제대로 고정이 안되는지는 모델의 구조를 파악해야할 것 같다

 

mesh quad와 triangle

이렇게 큐브가 사각형 quad 로 이루어져 있으면 곤란하다

쪼개서 triangle로 바꿔보자

지금은 cube라서 직접 할 수 있지만 이게 100개 이상 vertex가 있는 모델이라면 그것도 힘들다

 

바꾸고 나서 확인해봐도 결과는 같았다

cloth를 이루는 구조상 어떤 edge와 어떤 edge가 붙어있고 떨어지는 건지에 대한 조건을 알아야 해결 가능하다 

 

일단 바닥부터 해결해볼까 

model vertex와 world 좌표계 맞추기

일단 여기서 떨어지고 있는 판의 네 vertex들은 각각 index가 1,3,5,7 인 vertex이다

 

이렇게 바닥을 이루고 있을 것이다

예상하는 수치라 일단 확인해보자 

(확인 후 아님을 알았다)

vertex debugger gui 만들기

이렇게 버튼을 누르거나 게이지를 조절하면 vertex index에 초록점을 표시하도록 

gui debugger를 만들었다

 

이상하게도 0~23까지 인덱스에 큐브의 각각 vertex가 지정되어있다

총 vertex가 24개라는 것인데 6개의 면의 각각 4개씩 vertex가 중복되어 있다

 

obj 파일을 parsing할 때 그렇게 된 것 같은데

그렇다고 한다면 obj의 vertex 구조보단 edge를 붙이는 방법을 먼저 탐구하는게 좋을 것 같다 

고정된 두 vertex 떼기

큐브가 되었건 판 한 쪽이 되었건 떨어지지 않는 면이 있는 것은 

PBD 코드에서 두 vertex를 고정하고 있기 때문이다 

 

이 부분을 찾아서 수정하고 떨어지는 vertex의 좌표를 확인해보자 

cloth.ts
  private init() {
    // Set top of cloth to have a mass of 0 to hold still
    // in order to get hanging from clothesline visual
    {
      // Variables to store top row
      let minX = Number.MAX_VALUE;
      let maxX = -Number.MAX_VALUE;
      let maxY = -Number.MAX_VALUE;

      for (let i = 0; i < this.numParticles; i++) {
        minX = Math.min(minX, this.positions[3 * i]);
        maxX = Math.max(maxX, this.positions[3 * i]);
        maxY = Math.max(maxY, this.positions[3 * i + 1]);
      }

      // Thickness of the edge to zero out(?)
      const eps = 0.000001;

      for (let i = 0; i < this.numParticles; i++) {
        const x = this.positions[3 * i];
        const y = this.positions[3 * i + 1];
        if (y > maxY - eps && (x < minX + eps || x > maxX - eps))
          // if (y > maxY - eps)
          this.invMass[i] = 0.0;
      }
    }
  }

여기 스크립트에서 질량을 0으로 설정하는 vertex가 빨래집게처럼 모델을 고정하는 부분에 해당한다 

코드를 보면 cube이 천장이 고정되었던 이유를 알 수 있다

 

모델에서 가장 Y값이 높이있고, X값이 양 끝 값인 경우 고정하는 것이다

개수는 상관없이 말이다 

 

이상하게도 원피스 모델의 경우는 고정되는 지점이 없는데

 

      for (let i = 0; i < this.numParticles; i++) {
        const x = this.positions[3 * i];
        const y = this.positions[3 * i + 1];
        if (y > maxY - eps && (x < minX + eps || x > maxX - eps))
          // if (y > maxY - eps)
          this.invMass[i] = 0.0;
      }

그것 아마 조건문에 && 연산자로 되어있기 때문에

모든 정점 중에 Y값이 가장 높은 동시에 X값도 최대 혹은 최소여야 고정되기 때문인 것으로 보인다 

 

이 기능을 없애면 잘 떨어지겠지?

 

예상대로 잘 떨어진다

이 상태에서 vertex의 y position과 world 좌표에서 height를 비교해봐야한다

 

정점의 position을 debug gui에 띄우자

vertex position debug

아 debugger 만들려고 했는데 바닥 높이가 안맞았던 원인을 찾아버렸다

 

일단 좌표계 문제일 거라고 예상은 했었지만 맞았다

 

  //#region plane object
  objPath = 'plane.obj'
  file = await customOBJLoader.load(objPath)
  planeMesh = customOBJLoader.parse(file)
  planeMesh.material = new MeshStandardMaterial({ color: 'red', wireframe: false, side:2})
  planeMesh.position.set(0,1,0)
  planeMesh.scale.set(0.5,0.5,0.5)
  //#endregion

planeMesh는 빨간 판이다

보면 position도 1로 설정했고, scale도 모든 축에 대해서 0.5로 설정했다

 

이걸 지우고 floor height와 plane(빨간 판 말고 바닥)의 높이를 같은 변수로 설정해서 테스트 해보면

설정하는 높이에 따라 바닥에 잘 안착한다 

 

그래도 position debugger는 필요할 것 같으니 구현하자

 

이렇게 구현하였고, position y를 보면 높이가 잘 표시된다

시작하면 -1에서 바닥에 닿으면 딱 설정했던 -2가 된다

 

왜 시작이 -1이지? 

 

o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 -1.000000 1.000000
vn -0.0000 -1.0000 -0.0000
vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.375000 0.750000
vt 0.125000 0.750000
s 0
# f 3/1/1 1/2/1 2/3/1 4/4/1
f 3/1/1 1/2/1 2/3/1
f 3/1/1 2/2/1 4/4/1

아마 모델 특성인 것 같다 

obj 파일에서 이미 y값이 -1로 시작하기 때문이다 

이 부분을 수정하면 되긴 하겠다 

728x90
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유