개발/three.js / / 2023. 2. 13. 15:53

[Capstone Project] 템플릿 vertex 적용 테스트 환경 만들기 - 4

반응형
※ 해당 글은 capstone 종합설계 프로젝트를 하면서 적었던 일지를 돌아보며 작성한 것입니다.

개발일지 2022.10.10

312의 경우에는 vertex 위치와 face 연결성을 합쳐서 그렇게 나왔다면, 208개의 경우를 그대로 넣은 경우 다르게 나오는 것이 맞을 것이다. 테스트해보자.

 

cube 로 테스트를 진행해보았는데, 예상했던 가설과 일치했다. cube의 경우 vertex array가 24개로 나온다. index는 36개로 나오는데, 여기서 24개는 cube vertex 8개를 float array로 바꾸었을 떄를 의미하므로, face관련 정보가 없는 only vertex position을 의미한다.

 

여기서 vertex filter를 거치면, vertex의 개수는 36개가 되고, 총 array length는 36*3 = 108개이다.

여기서 9개씩 끊어서 (3개의 vertex 즉 하나의 polygon을 의미) 확인해본 결과, 하나의 폴리곤 씩 잘 생성되어서, 36개의 vertex가 모두 사용된 것을 확인할 수 있었다.

 

따라서 처음 모델을 가져왔을 때에는 attributes position에 vertex는 face가 포함되지 않은 정보이고, index를 통해 mapping하고 나면 position에 face정보가 포함된다.

이제 선택한 vertex의 인덱스를 가져오는 모듈을 만들어야하고 (getFiltedVertexIndex), 해당 인덱스 vertex의 좌표값을 수정하는 모듈도 필요하다. 언제까지 vertex float array안에서 수정할 수는 없기에, vertex index를 지정해서 수정하는 모듈도 필요하다.

 

부동 소수점 issue

 하아… float 부동소수점에서 소수점 뒷자리로 갈수록 오차가 생기는 오류 때문에 formating module들을 바꾸어야한다. floor로 6자리까지 잘라야하는데, 이제 mapping과정에서 기존 vertex position array값(floor하지 않은 값)과 일치하지 않다보니 또 문제이다.

 생각해보니 근데 별거 아닌 것 같다. mapping array와 filted array 모두 다 바꿔야하는데 한쪽만 바꿔서 좌표 mapping이 안되었던 문제였다.

 부동소수점 floor를 써도, 버림 개념이 아니라 가장 가까운 작은 수라서 음수의 경우 반올림된다.

음수인 경우에 floor를 사용하면 버리는게 아니라 올림이 되므로, 음수인 경우에는 ceil로 처리하는 방법으로 모듈을 수정하자.

 

결국 6자리까지 나오도록 toFixed로 반올림하는 것으로 정했다. 적어도 소수점 7번째에서 오차가 나지는 않으리라 생각하면서..

 

 위와 같이 하여도 문제가 발생한다. 이거 방법을 바꾸어야겠다. fixed처리로 소수점 6자리로 만들어도 attributes position array에 넣는순간 다시 float32로 바뀌면서 오차가 생긴다. 비교할 때만 fixed처리를 해서 비교하는 방향으로 바꾸자.

export default (object, vertex, filtedVertexVectorArray)=>{
    // (essential) transform to world position
    vertex = vector3Floor6(object.localToWorld(vertex)); 

    console.log(`vertex :`)
    console.log(vertex)
    console.log(`filted : `)
    console.log(filtedVertexVectorArray)

위 코드를 돌리면서 vertex와 filtedVertexVectorArray사이에서

0.21035111043602228

0.2103511095046997

이렇게 같은 점인데도 좌표차이가 나서 같은 좌표가 아닌것으로 체크된다… 

 

import * as THREE from 'three'

export default (vector3)=>{
    const resultVec = new THREE.Vector3(
        parseFloat(vector3.x.toFixed(4)),
        parseFloat(vector3.y.toFixed(4)),
        parseFloat(vector3.z.toFixed(4))
    )

    return resultVec
}

그래서 6자리 toFixed가 아니라 4자리로 변경하였다. float 좌표 상에서 오차가 6~7자리부터 발생하는 모양이라 toFixed로 반올림했을 값이 다르게 나올 확률이 점점 증가한다.

 

혹시나 docs의 Vector3.equal() 함수를 사용하면 처리해줄까 싶었지만,

 

if(new THREE.Vector3(vertex).equals(element)){
            filtedVertexIndex = index
            return true;
        }

이게 localToWorld를 통해 행렬처리를 할 때 오차가 생기는 것인데 이를 보정해주지는 못한 모양이다.

 

결국 오차범위를 포함해서 소수점 4자리까지 일치하면 같은 좌표로 취급하도록해서 인덱스를 찾을 수 있도록 하였다.

 

아.. 이래서 vertex를 직접 건드리면 안되는구나.. polygon을 구성하는 각 vertex 간의 거리가 지금처럼 충분히 떨어져있다면 다행이지만 polygon이 정말 많은 경우에는 소수점 4자리 수까지 일치하는 것이 안되는 경우도 생길 수 있다. 행렬연산을 할 때 바뀌는 부동 소수점도 vertex의 상당한 골칫거리이다…

 

addEventListener 순서

function addListenerClick(){
    window.addEventListener('click', function() {
        console.log(raycastVertexDebugger.getClickVertexIndex())
        clickVertexIndexGUI.setValue(raycastVertexDebugger.getClickVertexIndex())
    });
}

같은 이벤트에 대한 add listener가 두 개있을 때 main.js의 window가 가장 먼저 실행되는데, 더 늦게 실행되고 싶은 경우 위 처럼 addListener함수를 만들고 나중에 event를 추가하면 된다.

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