Three.js에서는 자주 사용되는 3D 도형을 쉽게 만들 수 있도록 다양한 기본 Geometry 클래스(Primitives)를 제공합니다.
아래는 대표적인 Primitives의 목록입니다:
기본 도형
BoxGeometry: 폭 × 높이 × 깊이 형태의 직육면체SphereGeometry: 반지름, 경도/위도 분할 설정 가능한 구체CylinderGeometry: 위/아래 반지름 설정 가능한 원기둥PlaneGeometry: 2D 면체, 바닥이나 벽처럼 사용 TorusGeometry: 중심이 뚫린 3D 링 구조고급 도형
ExtrudeGeometry: 2D 도형을 3D로 돌출TextGeometry: 텍스트를 3D 메쉬로 표현TubeGeometry: 경로를 따라 튜브(관) 형태 생성Three.js에서 Geometry는 점(vertex)과 면(face)으로 구성된 3D 도형의 기본 구조입니다.
예전 버전에서는 THREE.Geometry 클래스를 사용해 정점과 면 정보를 직접 배열에 넣는 방식으로 모델을 구성했습니다.
const geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(1, 0, 0),
new THREE.Vector3(0, 1, 0)
);
geometry.faces.push(new THREE.Face3(0, 1, 2));
이 방식은 직관적인 대신 성능이 떨어지고 메모리 낭비가 많아, 최신 버전에서는 더 이상 사용되지 않습니다.
Three.js r125 버전 이후로
Geometry는 완전히 제거되었습니다. 현재는BufferGeometry만 사용됩니다.
BufferGeometry는 현재 Three.js에서 기본이자 표준으로 사용되는 Geometry 클래스입니다.
정점 데이터를 TypedArray 형태로 저장하여 GPU가 직접 읽을 수 있게 함으로써, 훨씬 더 빠르고 효율적인 렌더링이 가능합니다.
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-1, -1, 0,
1, -1, 0,
1, 1, 0
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
import * as THREE from "https://unpkg.com/three@0.150.0/build/three.module.js";
import {OrbitControls} from "https://unpkg.com/three@0.150.0/examples/jsm/controls/OrbitControls.js";
import {FontLoader} from "https://unpkg.com/three@0.150.0/examples/jsm/loaders/FontLoader.js";
import {TextGeometry} from "https://unpkg.com/three@0.150.0/examples/jsm/geometries/TextGeometry.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._setupControls();
window.onresize = this.resize.bind(this);
this.resize();
requestAnimationFrame(this.render.bind(this));
}
_setupControls() {
new OrbitControls(this._camera, this._divContainer);
}
_setupCamera() {
const width = this._divContainer.clientWidth;
const height = this._divContainer.clientHeight;
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 100);
camera.position.x = -15;
camera.position.z = 15;
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);
}
_setupModel() {
const fontLoader = new FontLoader();
async function loadFont(that) {
const url = "https://unpkg.com/three@0.150.0/examples/fonts/helvetiker_regular.typeface.json";
const font = await new Promise((resolve, reject) => {
fontLoader.load(url, resolve, undefined, reject);
});
const geometry = new TextGeometry("Three", {
font: font,
size: 5,
height: 1.5,
curveSegments: 4,
bevelEnabled: true,
bevelThickness: 0.7,
bevelSize: 0.7,
bevelSegments: 3,
});
const fillMaterial = new THREE.MeshPhongMaterial({color: 0x515151});
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);
that._scene.add(group);
that._cube = group;
}
loadFont(this);
}
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 = () => {
new App();
};
