three.js Custom Geometry 1/3

Kleinstein·2022년 12월 19일
0

Three.js 관련

목록 보기
3/5

원문

다음의 글은 위의 사이트 내용을 번역한 것이다.

Three.js 에 기본적으로 포함된 기본(primitive) 지오메트리(Geometry) 에 대해서는 이미 존재하는 지오메트리 클래스들의 리스트를 보고 하나씩 호출하면서 적절한 파라메터를 주는 것으로 화면에 해당 지오메트리를 생성하고 보여줄수 있다.

기본으로 제공되는 Geometry 클래스들

    BoxGeometry
    CircleGeometry
    ConeGeometry
    CylinderGeometry
    DodecahedronGeometry
    EdgesGeometry
    ExtrudeGeometry
    IcosahedronGeometry
    LatheGeometry
    OctahedronGeometry
    PlaneGeometry
    PolyhedronGeometry
    RingGeometry
    ShapeGeometry
    SphereGeometry
    TetrahedronGeometry
    TorusGeometry
    TorusKnotGeometry
    TubeGeometry
    WireframeGeometry

이와는 다른, 내가 원하는 지오메트리를 생성하는 법에 대해 알아보기 위해 좀 검색을 하다가 적절한 강좌인것 같아서 일단 대략적으로 번역/의역해보기로 했다.

대충 의미만 통하도록 번역/의역 한 것임을 밝힌다.


정말 원하는 3D 모델을 만들기 위한 가장 일반적인 방법은 전문적인 3D 모델링 프로그램을 사용하는 것이다.

이런 프로그램으로는 Blender, Maya, 3D Studio Max, Cinema4D 등 유명한 프로그램들이 매우 많다.

이렇게 3D 모델링 프로그램으로 일단 원하는 3D 모델을 만든다음, .gLTF 나 .obj 포맷으로 export 하고, 이렇게 export 된 3D 모델을 다시 읽어들이는 것이 웹브라우저에 해당 모델을 보여주는 방법으로는 가장 효율적이다.

물론 3D 모델링 프로그램중 어떤걸 선택하던지 2 - 3주 이상 3D 모델링 프로그램의 사용법을 배워야 한다는 것은 염두에 두어야 한다.

그런데, 이런 프로그램들이 있음에도 불구하고 우리는 우리가 원하는 3D 모델을 코딩을 통해 직접 만들고 싶을 수도 있다.

이렇게 코딩을 통해 3D모델을 만드는 법을 알아보기 위해 먼저 간단한 정육면체 큐브를 만들어 보자. three.js 가 제공하는 BoxGeometry 와 BoxBufferGeometry 큐브는 이해하기 쉽기 때문에 여기서 부터 시작하면 좋을것 같다.

three.js 에서 custom Geometry 를 만드는 데에는 2가지 방법이 있다.

하나는 Geometry 클래스를 사용하는 것이고, 또 하나는 BufferGeometry 클래스를 사용하는 방법이다. 이 두 가지 방법은 각각 장단점이 있다.

Geometry 클래스는 사용하기는 쉽지만 좀 느린편이고 더 많은 메모리를 사용한다. 약 수천개 가량의 삼각형으로 이루어진 모델의 경우 Geometry 클래스는 최선의 선택이 될 수 있지만 수만개 가량의 삼각형을 가진 모델을 위해서는 BufferGeometry 클래스를 사용하는 것이 더 좋다.

BufferGeometry 클래스는 사용하기는 어렵지만 더 적은 메모리를 사용하면서 더욱 빠르다. 대략 만개 이상의 삼각형으로 이루어진 모델이라면 BufferGeometry 클래스를 사용하는 것을 추천한다.

오해하지 말아야 할 것은 Geometry 클래스가 느리다고 표현한 이유는 시작하는데 좀 느리고 모델의 형상을 바꾸는 경우가 있을때 느리다는 것이지, 모델 자체를 그려내는 시간 자체는 전혀 느리지 않다. 그러므로 3D 모델을 만든다음 형상을 변형시키는 일이 없거나, 그리 크고 복잡한 모델이 아니라면 Geometry 클래스를 사용하는것도 나쁘지 않다.

우리는 두 가지 클래스를 모두 다룰 것이다. 일단 지금은 IMO(??)를 더 쉽게 이해하기위해 Geometry클래스를 먼저 다뤄보자.

우선 Geometry 클래스로 큐브를 만들어보자.

먼저 primitive Geometry 로 주어진 BoxGeometry 를 사용하는 방법은 아래와 같다.

    const boxWidth = 1;
    const boxHeight = 1;
    const boxDepth = 1;
    const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);

위의 방법을 Geometry 클래스를 사용하는 방법으로 바꾸기 위해, 위의 코드를 우선 아래의 코드로 바꾸어 보자.

    const geometry = new THREE.Geometry();

이 그림에서, 큐브 내부의 정 가운데가 좌표의 원점이다.

그리고 위 그림과 같은 큐브를 만들기 위해 우선 아래의 코드를 사용한다. (0에서 7까지의 점Vertex의 위치 좌표값들을 이런 식으로 넣어준다.)

    const geometry = new THREE.Geometry();
    geometry.vertices.push(
      new THREE.Vector3(-1, -1,  1),  // 0
      new THREE.Vector3( 1, -1,  1),  // 1
      new THREE.Vector3(-1,  1,  1),  // 2
      new THREE.Vector3( 1,  1,  1),  // 3
      new THREE.Vector3(-1, -1, -1),  // 4
      new THREE.Vector3( 1, -1, -1),  // 5
      new THREE.Vector3(-1,  1, -1),  // 6
      new THREE.Vector3( 1,  1, -1),  // 7
    );

이렇게 각 점들의 위치좌표를 넣어준 다음 이 점들로 삼각형을 만들어 주어야 한다. 이는 아래와 같이 정육면체의 각 면을 2개의 삼각형으로 만들어주면 된다.

삼각형을 만들어주기 위해서 three.js 의 Face3 이라는 객체를 사용하고 거기에 삼각형을 이루는 세 점의 인덱스 값을 지정해준다.

이 때 인덱스를 지정하는 순서가 매우 중요하다.

카메라가 위치한 큐브의 바깥 방향으로 인덱스 순서가 정의되어야 하는데, 삼각형이 카메라에 보이게끔 하기위해서는 카메라가 큐브 밖에 있다는 전제하에 시계 반대 방향 순서에 맞게 삼각형의 세 점이 지정되어야 한다. 아래의 그림을 참조해보자.

카메라가 0123 으로 이루어진 큐브 면의 바깥쪽에 위치하고 있고 이 카메라에 삼각형이 보이게끔 하려면, 이렇게 녹색 화살표의 방향 순서대로 삼각형의 각 점이 지정되어야 한다.

즉, 삼각형을 이루는 각 점의 인덱스를 순서에 맞게 아래와 같이 총 12개의 삼각형으로 지정해준다.

    geometry.faces.push(
      // front
      new THREE.Face3(0, 3, 2),
      new THREE.Face3(0, 1, 3),
      // right
      new THREE.Face3(1, 7, 3),
      new THREE.Face3(1, 5, 7),
      // back
      new THREE.Face3(5, 6, 7),
      new THREE.Face3(5, 4, 6),
      // left
      new THREE.Face3(4, 2, 6),
      new THREE.Face3(4, 0, 2),
      // top
      new THREE.Face3(2, 7, 6),
      new THREE.Face3(2, 3, 7),
      // bottom
      new THREE.Face3(4, 1, 0),
      new THREE.Face3(4, 5, 1),
    );

이렇게 만든 삼각형들에 아직 normal (vector) 를 정해주지 않았으므로 light를 사용할수는 없다. 그래서 light에 구애받지 않는 material을 만들기 위해, MeshBasicMaterial 을 사용해서 Material 을 만들어주고 이 Material 과 geometry 를 합쳐서 아래와 같이 Mesh를 만들어준다.

  const material = new THREE.MeshBasicMaterial({color});
  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);

이제 큐브의 각 면에 각각 서로 다른 색깔을 지정해주려면 아래와 같이 각 면에 색깔을 우선 지정해줄수 있다.

    geometry.faces[ 0].color = geometry.faces[ 1].color = new THREE.Color('red');
    geometry.faces[ 2].color = geometry.faces[ 3].color = new THREE.Color('yellow');
    geometry.faces[ 4].color = geometry.faces[ 5].color = new THREE.Color('green');
    geometry.faces[ 6].color = geometry.faces[ 7].color = new THREE.Color('cyan');
    geometry.faces[ 8].color = geometry.faces[ 9].color = new THREE.Color('blue');
    geometry.faces[10].color = geometry.faces[11].color = new THREE.Color('magenta');

그리고 이렇게 각 면에 색을 정한 것으로 material 을 만들려면 THREE.FaceColors 를 사용하여 material을 만들것이라고 아래와 같이 파라메터를 지정해 주어야 한다.

const material = new THREE.MeshBasicMaterial({vertexColors: THREE.FaceColors});

여기서 vertexColors 라고 미리 지정된 속성값에 THREE.FaceColors 라는 값을 지정해주는데, 이는 Geometry의 모든 색은 항상 Vertex 를 기준으로 정해지기 때문이다.

삼각형의 세 점이 동일한 색을 지니고 있다면 이 삼각형이 이루는 면의 색도 역시 같은 색을 띄게 된다.

또한 좀 전에 지정한 삼각형 면의 색깔로 인해 똑같은 색이 삼각형의 세 점에 지정되면 당연히 삼각형 면의 색깔이 동일한 색으로 표현된다.

그래서 three.js 에서 Material 지정시에 vertexColors 라는 속성값에 적절한 파라메터를 지정함으로써 면과 각 점의 색을 어떻게 표현할지 결정할수 있다.

(일반적으로 직접 이어진 두 점에 서로 다른 색을 지정하고 적절한 옵션을 정하면 이 두 점의 색이 중간에서 자연스럽게 변하면서 해당 색으로 변하는것 처럼 보이게 된다.)

profile
developer in germany

0개의 댓글