[Three.js] 지오메트리(Geometry) Part 1

HYl·2022년 3월 24일
1

Three.js

목록 보기
2/3

이전의 글에서는 geometry에 육면체의 형상을 정의하는 BoxGeometry를 사용해 보았다. 이번 글에서는 BoxGeometry를 포함하여 three.js에서 제공하는 기본 지오메트리들을 살펴 볼 것이다.

  • Three.js에서 기본적으로 제공하는 지오메트리이다.
  • 지오메트리는 기본적으로 BufferGeometry 를 상속받고 있다.
  • ParametricGeometry 는 수학적 함수식에 2개의 값을 입력하여 얻을 수 있는 좌표로 구성되는 지오메트리이다.
  • EdgesGeometry 는 지오메트리를 구성하는 인접면의 각도에 따라 지오메트리를 재구성한다.
  • PolyhedrongGeometry 는 다면체를 구성하는 지오메트리이다.
    • PolyhedrongGeometry를 상속받는 IcosahedronGeometry 는 20면체, OctahedronGeometry 8면체 DodecahedronGeometry 는 12면체, TetrahedronGeometry는 4면체 지오메트리이다.

  • Geometry 는 3차원 Object의 형상을 정의한다. 위의 사진은 이것을 정의하기 위한 데이터를 나타낸다.
  • Vertex : 형상을 정의하는 정점 , xyz 축에 대한 좌표이다.
  • Vertex Index : 3차원 오브젝트의 면을 구성하는 정점에 대한 인덱스
  • Normal Vector : 정점에 대한 수직 벡터
  • Vertex Color : 백터 정점의 색상
  • 텍스쳐 맵핑을 위한 UV 좌표
  • 사용자가 임의로 정의한 데이트

위의 데이터들은, 3차원으로 시각화될 때 GPU에 한 번에 전달되어 빠르게 처리된다.


WireframeGeometry

이전의 글에서 작성하였던 _setupModel() 함수를 살펴보자.
변경 후가, WireframeGeometry을 추가하여 살펴 볼 코드이다.

_setupModel() {
    /***** 변경 전 *****/  
    // const geometry = new THREE.BoxGeometry(1, 1, 1);
    // const material = new THREE.MeshPhongMaterial({ color: 0x44a88 });

    // const cube = new THREE.Mesh(geometry, material);

    // this._scene.add(cube);
    // this._cube = cube;

    /***** 변경 후 *****/
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const fillMaterial = new THREE.MeshPhongMaterial({ color: 0x44a88 });
    const cube = new THREE.Mesh(geometry, fillMaterial);

    // 선 추가
    const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffff00 });
    const line = new THREE.LineSegments(
        new THREE.WireframeGeometry(geometry), // WireframeGeometry : 와이어프레임 형태로 지오메트리를 표헌
        lineMaterial
    );

    const group = new THREE.Group();
    group.add(cube);
    group.add(line);

    this._scene.add(group);
    this._cube = group;
}

만약, WireframeGeometry 를 없앤다면

  const line = new THREE.LineSegments(geometry, lineMaterial);

모델의 모든 외곽선이 표시되지 않을 것이다.


이제 사용자가 마우스를 이용해 정육면체를 회전 시킬 수 있는 코드를 작성해 볼 것이다.

import { OrbitControls } from "./OrbitControls.js";

OrbitControls를 먼저 Import 해오자, 이전의 압축을 풀었던 파일 안에 examples/jsm/controls/OrbitControls 에 존재한다.

_setControls() {
    // OrbitsControls 객체를 생성할 때는 카메라 객체와 마우스 이벤트를 받는 DOM 요소가 필요하다.
    new OrbitControls(this._camera, this._divContainer);
}

_setControls 함수를 작성하면, 사용자가 마우스를 이용하여 회전 시킬 수 있다.

_setupModel() {
    const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2);
    const fillMaterial = new THREE.MeshPhongMaterial({ color: 0x44a88 });
    const cube = new THREE.Mesh(geometry, fillMaterial);

    // 선 추가
    const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffff00 });
    const line = new THREE.LineSegments(
        new THREE.WireframeGeometry(geometry), // WireframeGeometry : 와이어프레임 형태로 지오메트리를 표헌
        lineMaterial
    );

    const group = new THREE.Group();
    group.add(cube);
    group.add(line);

    this._scene.add(group);
    this._cube = group;
}

BoxGeometry는 가로, 세로, 깊이에 대한 크기와함께 가로, 세로, 깊이 각각에 대한 분한 즉 Segments 수로 정의된다.

  • 가로,세로,깊이에 대한 분할수는 지정하지 않으면 기본 값은 1이다.
  • 모두 2로 지정하게 되면? 가로, 세로, 깊이 방향으로 2개씩 분할되어진다.


전체 JS 코드

import * as THREE from "../build/three.module.js";
import { OrbitControls } from "./OrbitControls.js";

class App {
	constructor() {
		const divContainer = document.querySelector("#webgl-container");
		this._divContainer = divContainer;

		const renderer = new THREE.WebGLRenderer({ antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		divContainer.appendChild(renderer.domElement);
		this._renderer = renderer;

		const scene = new THREE.Scene();
		this._scene = scene;

		this._setupCamera();
		this._setupLight();
		this._setupModel();
		this._setControls();

		window.onresize = this.resize.bind(this);
		this.resize();

		requestAnimationFrame(this.render.bind(this));
	}

	_setupCamera() {
		const width = this._divContainer.clientWidth;
		const height = this._divContainer.clientHeight;
		const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100);
		camera.position.z = 2;
		this._camera = camera;
	}

	_setupLight() {
		const color = 0xffffff;
		const intensity = 1;
		const light = new THREE.DirectionalLight(color, intensity);
		light.position.set(-1, 2, 4);
		this._scene.add(light);
	}

	_setControls() {
		new OrbitControls(this._camera, this._divContainer);
	}

	_setupModel() {
		const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2);
		const fillMaterial = new THREE.MeshPhongMaterial({ color: 0x44a88 });
		const cube = new THREE.Mesh(geometry, fillMaterial);

		// 선 추가
		const lineMaterial = new THREE.LineBasicMaterial({ color: 0xffff00 });
		const line = new THREE.LineSegments(
			new THREE.WireframeGeometry(geometry), 
			lineMaterial
		);

		const group = new THREE.Group();
		group.add(cube);
		group.add(line);

		this._scene.add(group);
		this._cube = group;
	}

	resize() {
		const width = this._divContainer.clientWidth;
		const height = this._divContainer.clientHeight;

		this._camera.aspect = width / height;
		this._camera.updateProjectionMatrix();

		this._renderer.setSize(width, height);
	}

	render(time) {
		this._renderer.render(this._scene, this._camera);
		this.update(time);
		requestAnimationFrame(this.render.bind(this));
	}

	update(time) {
		time *= 0.001;
		this._cube.rotation.x = time;
		this._cube.rotation.y = time;
	}
}

window.onload = function () {
	new App();
};
profile
꾸준히 새로운 것을 알아가는 것을 좋아합니다.

0개의 댓글