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

Threejs Cloth Tailor 개발일지 - compute bounding sphere, enum type 단점과 object literal type, mesh cut

728x90
반응형

 

compute bounding sphere 함수 (bounding box)

stack overflow의 한 사람이 해결한 방법으로 compute bounding sphere를 알려주었는데

이게 무슨 함수인가 

 

bounding box 혹은 boudning sphere라고 하면 해당 geometry를 포함하는 일정 영역을 말하는 것인데 

이걸 수동적으로 계산하게 함으로써 혹여나 geometry의 vertice들의 update에 대해서 raycast나 frustum culling에서 잘 반응하도록 하는 것이다

 

즉 custom한 mesh의 경우, 엔진이 제공하는 raycast함수가 변화하는 vertices를 제대로 감지하지 못해서 생긴 일이라고 생각하면 또 맞는 말 같다. 

 

실제로 지금 프로젝트에서는 PBD시뮬레이션을 통해 particle들이 움직이므로 그럴듯 하긴 한데,

이미 바닥에 떨어져있는 상태임에도 감지하지 못하는 것은...

 

일단 plane 형태의 모델을 사용하므로 bounding box를 사용해보자. 

 

async function animate() {
  await requestAnimationFrame(animate)

  //#region simulation
  if(!stateStop) physicsSimulation()
  //#endregion

  if (resizeRendererToDisplaySize(renderer)) {
    const canvas = renderer.domElement
    camera.aspect = canvas.clientWidth / canvas.clientHeight
    camera.updateProjectionMatrix()
  }

  cameraControls.update()
  gui.updatePositionGui(currentMesh)

  currentMesh.geometry.computeBoundingBox()

  renderer.render(scene, camera)

사용했는데 크게 티는 안난다. 

raycast가 line과 충돌하는 현상에 대해서 수정을 좀 해보자

 

raycast 충돌 labeling

라벨링이라고 해도 될지는 모르겠지만, 일단 스스로 쏜 line과는 적어도 충돌체크하지 않도록 한다 

 

이상한 점은 빨간색 plane을 체크하게 되면 line이 (0,0,0) positoin위에 뜬다는 점이다

geometry는 수정이 되었지만 마치 position은 수정이 되지 않았다는 듯이 말이다 

 

export function clickPoint(scene: Scene, camera: Camera){
  raycaster.setFromCamera(mouse, camera)
  const intersects = raycaster.intersectObjects(scene.children)

  if (intersects.length > 0) {
    for(let i = 0; i < intersects.length; i++){
      const intersect = intersects[i]
      if(intersect.object === gizmoLine) continue

      const intersectedObject = intersect.object
      const intersectPoint = intersect.point
      
      console.log(intersectedObject.name)

      drawLine(scene, camera.position, intersectPoint)
      break
    }
  }
}

intersect 로직을 수정했더니 좀 잘 되는 편인데

각도에 따라서 red plane이 감지가 안되는 각도가 있는 것 같다 

 

export function init(scene: Scene, camera: Camera): Raycaster{
  window.addEventListener('mousemove', onMouseMove, false)

  const viewInterFunc = ()=>viewIntersectPoint(scene, camera)

  window.addEventListener('mousedown', ()=>{
    window.addEventListener('mousemove', viewInterFunc, false)
  }, false)
  window.addEventListener('mouseup', ()=>{
    window.removeEventListener('mousemove', viewInterFunc, false)
    gizmoLine.clear()
  }, false)

  return raycaster
}

클릭이 아니라 누르고 있으면 연속적으로 raycast가 업데이트 되도록 하자 

 

혹시 몰라서 겹치는 바닥도 없애고 테스트를 해보다가 문득 bounding box로 하면 그대로 plane형태일테니,

bounding sphere로 하면 영역이 넓어지지 않을까 하는 생각이 들었다

 

async function animate() {
  await requestAnimationFrame(animate)

  //#region simulation
  if(!stateStop) physicsSimulation()
  //#endregion

  if (resizeRendererToDisplaySize(renderer)) {
    const canvas = renderer.domElement
    camera.aspect = canvas.clientWidth / canvas.clientHeight
    camera.updateProjectionMatrix()
  }

  cameraControls.update()
  gui.updatePositionGui(currentMesh)

  currentMesh.geometry.computeBoundingSphere()

  renderer.render(scene, camera)
}

compute bound box에서 sphere로 변경하고 테스트를 해보니

그때부터 막힘없이 모든 plane의 표면이 감지 되었다 

 

확실히 sphere로 설정하니 영역이 넓어져서 잘 감지할 수 있도록 된 것이다 

 

mode에 따라 기능 분리

mode를 만들어놓고 raycast를 그냥 붙여놓으니 카메라 회전과 raycast 기능이 분리가 안된다

분리해놓자

 

Typescript에서의 enum 단점과 object literal 대체

아오 JS에서는 되는 방법인데 TS에서는 자꾸 에러가 나서 불편하다. 

그렇다고 TS상에서 type을 일치시키면 비교가 정상적으로 안되서 로직이 안된다.

 

TS에서 이러한 단점이 enum에 대해서 이미 만연한가보다

그래서 object literal을 대신 사용한다는데

 

export enum Mode{
  NONE, RAYCAST
}
type Mode2 = "NONE" | "RAYCAST"

이렇게 바꾸는 방법이다

불편한 enum을 쓰지 말고 바로 다 대체해버리자

TS를 잘 모르다 보니 이런 부분들은 처음 알았다..

 

mesh cut 로직에 대해서 

평면 mesh를 자르는 방법은 어렵다.

 

Splitting cubes: a fast and robust technique for virtual cutting

이렇게 자르기 선을 긋게 되면 vertices의 구조를 바꿀 필요가 있다 

그래서 방법은 vertex를 지우기만 하는 방법과, 위 그림처럼 선에 다라 새로운 vertices를 추가하고 지우고 해서 구조를 바꾸는 방법이 있다

 

근데 문제는 구조를 바꾸면 PBD 시뮬레이션이 어떻게 동작할지 예상이 안된다는 것.

그래서 일단 raycast로 vertex를 debugging해서 지우고 서로 다른 mesh로 분리하는 것이 우선이 된다

 

 

 

raycast를 point에서 가까운 vertex들을 가리키는 방향으로 수정하고,

vertices들을 클릭해서 지우는 기능을 만들자.

 

그 다음에는 서로 분리된 mesh로 분리하여 각각 따로 시뮬레이션을 할 수 있게 만들어보자 

거기까지 된다면 그 다음은 원단을 붙이는 기능을 하고 싶다. 

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