_setupModel() {
// Shape 클래스 생성
const shape = new THREE.Shape();
// x,y 좌표로 도형 정의
// (1,1) 로 이동 -> (1, -1)까지 선 그음 -> (-1, -1)까지 선 그음 -> (-1, 1)까지 선 그음
shape.moveTo(1, 1);
shape.lineTo(1, -1);
shape.lineTo(-1, -1);
shape.lineTo(-1, 1);
// 도형을 닫으라고 지정
shape.closePath();
const geometry = new THREE.BufferGeometry();
const points = shape.getPoints();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xffff00 });
const line = new THREE.Line(geometry, material);
this._scene.add(line);
}
_setupModel() {
// Shape 클래스 생성
const shape = new THREE.Shape();
const x = -2.5, y = -5;
shape.moveTo(x + 2.5, y + 2.5);
shape.bezierCurveTo( x + 2.5, y + 2.5, x + 2, y, x, y);
shape.bezierCurveTo(x - 3, y, x - 3, y + 3.5, x - 3, y + 3, 5);
shape.bezierCurveTo(x - 3, y + 5.5, x - 1.5, y + 7.7, x + 2.5, y + 9, 5);
shape.bezierCurveTo(x + 6, y + 7.7, x + 8, y + 4.5, x + 8, y + 3.5);
shape.bezierCurveTo(x + 8, y + 3.5, x + 8, y, x + 5, y);
shape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
const geometry = new THREE.BufferGeometry();
const points = shape.getPoints();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xffff00 });
const line = new THREE.Line(geometry, material);
this._scene.add(line);
}
_setupModel() {
// shape
const shape = new THREE.Shape();
const x = -2.5, y= -5;
shape.moveTo(x + 2.5, y + 2.5);
shape.bezierCurveTo(x + 2.5, y + 2.5, x + 2, y, x, y);
shape.bezierCurveTo(x - 3, y, x - 3, y + 3.5, x - 3, y + 3.5);
shape.bezierCurveTo(x - 3, y + 5.5, x - 1.5, y + 7.7, x + 2.5, y + 9.5);
shape.bezierCurveTo(x + 6, y + 7.7, x + 8, y + 4.5, x + 8, y + 3.5);
shape.bezierCurveTo(x + 8, y + 3.5, x + 8, y, x + 5, y);
shape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
// ShapeGeometry의 생성자에 인자로 shape 객체를 전달함
const geometry = new THREE.ShapeGeometry(shape);
// 회색 색상의 재질로 mesh 타입 오브젝트 생성
const fillMaterial = new THREE.MeshPhongMaterial({ color: 0x515151 });
const cube = new THREE.Mesh(geometry, fillMaterial);
// 노란색 선 재질 생성
const lineMaterial = new THREE.LineBasicMaterial({color: 0xffff00});
// 앞에서 만든 geometry를 이용해 line타입 오브젝트 생성
/*
WireframeGeometry 클래스: 와이어프레임 형태로 지오메트리 표현
만약 WireframeGeometry 적용하지 않고 생성하면 모델의 모든 외곽선이 표시되지 않음.
*/
const line = new THREE.LineSegments(
new THREE.WireframeGeometry(geometry), lineMaterial);
// mesh 오브젝트와 line 오브젝트를 하나의 오브젝트로 다루기 위해 그룹으로 묶음
const group = new THREE.Group()
/*
cube를 삭제하면 노란색 line만 보임,
line을 삭제하면 회색 cube만 보임
*/
group.add(cube);
group.add(line);
// 그룹 객체를 scene에 추가
this._scene.add(group);
this._cube = group;
}
카메라 시점 조절
- _setupCamera()의 camera.position.z를 15로 늘려준다. 그러면 카메라 시점이 멀어짐
camera.position.z=15;
_setupModel() {
// Curve 클래스를 상속받은 CustomSinCurve 클래스 정의
// curve를 t 매개변수 방정식으로 정의함
class CustomSinCurve extends THREE.Curve {
constructor(scale) {
super();
this.scale = scale;
}
// 0~1 사이의 t값에 대한 curve의 구성 좌표 계산
getPoint(t) {
const tx = t * 3 - 1.5;
const ty = Math.sin(2 * Math.PI * t);
const tz = 0;
return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
}
}
const path = new CustomSinCurve(4);
const geometry = new THREE.BufferGeometry();
// 좀더 부드러운 곡선을 얻으려면 getPoints 인자에 적당한 정수값 지정(기본값 5)
// 인자값 -> curve를 구성하는 좌표의 개수
const points = path.getPoints(30);
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xffff00 });
const line = new THREE.Line(geometry, material);
this._scene.add(line);
}
const points = path.getPoints();
일때
const points = path.getPoints(30);
일때
_setupModel() {
class CustomSinCurve extends THREE.Curve {
constructor(scale) {
super();
this.scale = scale;
}
getPoint(t) {
const tx = t * 3 - 1.5;
const ty = Math.sin(2 * Math.PI * t);
const tz = 0;
return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
}
}
// tube가 이어지는 형태를 결정하기 위한 curve 객체 생성
const path = new CustomSinCurve(4);
// path라는 curve 객체를 TubeGeometry의 생성자에 전달함
// TubeGeometry는 5개의 인자를 받음
// 1. path
// 2. tube의 진행 방향에 대한 분할 수(기본값 64)
// 3. tube의 원통에 대한 반지름 크기(기본값 1)
// 4. 원통에 대한 분할 수(기본값 8)
// 5. 원통의 끝 단을 닫을지에 대한 여부(기본값 false)
const geometry = new THREE.TubeGeometry(path);
// 회색 색상의 재질로 mesh 타입 오브젝트 생성
const fillMaterial = new THREE.MeshPhongMaterial({ color: 0x515151 });
const cube = new THREE.Mesh(geometry, fillMaterial);
// 노란색 선 재질 생성
const lineMaterial = new THREE.LineBasicMaterial({color: 0xffff00});
// 앞에서 만든 geometry를 이용해 line타입 오브젝트 생성
/*
WireframeGeometry 클래스: 와이어프레임 형태로 지오메트리 표현
만약 WireframeGeometry 적용하지 않고 생성하면 모델의 모든 외곽선이 표시되지 않음.
*/
const line = new THREE.LineSegments(
new THREE.WireframeGeometry(geometry), lineMaterial);
// mesh 오브젝트와 line 오브젝트를 하나의 오브젝트로 다루기 위해 그룹으로 묶음
const group = new THREE.Group()
/*
cube를 삭제하면 노란색 line만 보임,
line을 삭제하면 회색 cube만 보임
*/
group.add(cube);
group.add(line);
// 그룹 객체를 scene에 추가
this._scene.add(group);
this._cube = group;
}
const geometry = new THREE.TubeGeometry(path, 40, 0.8, 8);
const geometry = new THREE.TubeGeometry(path, 40, 0.8, 8, true);
_setupModel() {
// points로 구성되는 좌표들이 이루는 선
const points = [];
for(let i = 0; i < 10; ++i) {
points.push(new THREE.Vector2(Math.sin(i * 0.2) * 3 + 3, (i - 5) * .8));
}
const geometry = new THREE.BufferGeometry();
geometry.setFromPoints(points);
const material = new THREE.LineBasicMaterial( { color: 0xffff00 });
const line = new THREE.Line(geometry, material);
this._scene.add(line);
}
_setupModel() {
// points로 구성되는 좌표들이 이루는 선
// -> 이 선을 y축으로 회전시켜 생성되는 3차원 mesh를 얻기위해 LatheGeometry를 사용함
const points = [];
for(let i = 0; i < 10; ++i) {
points.push(new THREE.Vector2(Math.sin(i * 0.2) * 3 + 3, (i - 5) * .8));
}
const geometry = new THREE.LatheGeometry(points);
// 회색 색상의 재질로 mesh 타입 오브젝트 생성
const fillMaterial = new THREE.MeshPhongMaterial({ color: 0x515151 });
const cube = new THREE.Mesh(geometry, fillMaterial);
// 노란색 선 재질 생성
const lineMaterial = new THREE.LineBasicMaterial({color: 0xffff00});
// 앞에서 만든 geometry를 이용해 line타입 오브젝트 생성
/*
WireframeGeometry 클래스: 와이어프레임 형태로 지오메트리 표현
만약 WireframeGeometry 적용하지 않고 생성하면 모델의 모든 외곽선이 표시되지 않음.
*/
const line = new THREE.LineSegments(
new THREE.WireframeGeometry(geometry), lineMaterial);
// mesh 오브젝트와 line 오브젝트를 하나의 오브젝트로 다루기 위해 그룹으로 묶음
const group = new THREE.Group()
/*
cube를 삭제하면 노란색 line만 보임,
line을 삭제하면 회색 cube만 보임
*/
group.add(cube);
group.add(line);
// 그룹 객체를 scene에 추가
this._scene.add(group);
this._cube = group;
}
const geometry = new THREE.LatheGeometry(points, 32, 0, Math.PI);
_setupModel() {
// heart shape
const x = -2.5, y= -5;
const shape = new THREE.Shape();
shape.moveTo(x + 2.5, y + 2.5);
shape.bezierCurveTo(x + 2.5, y + 2.5, x + 2, y, x, y);
shape.bezierCurveTo(x - 3, y, x - 3, y + 3.5, x - 3, y + 3.5);
shape.bezierCurveTo(x - 3, y + 5.5, x - 1.5, y + 7.7, x + 2.5, y + 9.5);
shape.bezierCurveTo(x + 6, y + 7.7, x + 8, y + 4.5, x + 8, y + 3.5);
shape.bezierCurveTo(x + 8, y + 3.5, x + 8, y, x + 5, y);
shape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
// ExtrudeGeometry settings
const settings = {
steps: 1,
depth: 4,
bevelEnabled: false,
bevelThickness: 0.1,
bevelSize: 0.1,
bevelSegments: 1,
};
const geometry = new THREE.ExtrudeGeometry(shape, settings);
// 회색 색상의 재질로 mesh 타입 오브젝트 생성
const fillMaterial = new THREE.MeshPhongMaterial({ color: 0x515151 });
const cube = new THREE.Mesh(geometry, fillMaterial);
// 노란색 선 재질 생성
const lineMaterial = new THREE.LineBasicMaterial({color: 0xffff00});
// 앞에서 만든 geometry를 이용해 line타입 오브젝트 생성
/*
WireframeGeometry 클래스: 와이어프레임 형태로 지오메트리 표현
만약 WireframeGeometry 적용하지 않고 생성하면 모델의 모든 외곽선이 표시되지 않음.
*/
const line = new THREE.LineSegments(
new THREE.WireframeGeometry(geometry), lineMaterial);
// mesh 오브젝트와 line 오브젝트를 하나의 오브젝트로 다루기 위해 그룹으로 묶음
const group = new THREE.Group()
/*
cube를 삭제하면 노란색 line만 보임,
line을 삭제하면 회색 cube만 보임
*/
group.add(cube);
group.add(line);
// 그룹 객체를 scene에 추가
this._scene.add(group);
this._cube = group;
}
// ExtrudeGeometry settings
const settings = {
steps: 1,
depth: 4,
bevelEnabled: false,
bevelThickness: 0.1,
bevelSize: 0.1,
bevelSegments: 1,
};
// ExtrudeGeometry settings
const settings = {
steps: 2,
depth: 4,
bevelEnabled: true,
bevelThickness: 1.6,
bevelSize: 2,
bevelSegments: 6,
};
ExtrudeGeometry의 파생 클래스
폰트 데이터 필요
ttf 등과 같은 폰트 파일을 three.js에서 폰트로 사용할 수 있는 포맷으로 변경해 사용함(형식 json)
폰트를 로드하기 위해서는 FontLoader 클래스 필요
const fontLoader = new THREE.FontLoader();
폰트 데이터를 비동기적으로 불러와야함
loadFont 비동기 함수 추가
_setupModel() {
// FontLoader 클래스
const fontLoader = new FontLoader();
// 폰트 데이터를 비동기적으로 불러오기 위한 비동기 함수
async function loadFont(that) {
const url = "../examples/fonts/helvetiker_regular.typeface.json";
const font = await new Promise((resolve, reject) => {
fontLoader.load(url, resolve, undefined, reject);
});
// TextGeometry 생성
const geometry = new TextGeometry("Scribubble", {
font: font,
size: 5,
height: 1.5,
curveSegments: 4,
// setting for ExtrudeGeometry
bevelEnabled: true,
bevelThickness: 0.7,
bevelSize: .7,
bevelSegments: 2
});
// 함수 내부에서 geometry 생성하고 있기때문에 아래 코드도 비동기 함수 내에서 호출
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;
};
// this인자와 함께 호출
loadFont(this);
}
강의 그대로 코드 입력을 했는데 아무것도 안떠서 원인이 뭘까 찾아보다가.. 유튜브 댓글에서 똑같은 에러메시지를 발견했다.
원인은 최근 three.js가 업데이트 되어 FontLoader와 TextGeometry가 더이상 THREE.~으로 참조되지 않는다고 한다.
import { FontLoader } from "../examples/jsm/loaders/FontLoader.js";
import { TextGeometry } from "../examples/jsm/geometries/TextGeometry.js";
const fontLoader = new FontLoader();
const geometry = new TextGeometry();
const geometry = new TextGeometry("Scribubble", {
font: font,
size: 5,
height: 1.5,
curveSegments: 4,
// setting for ExtrudeGeometry
bevelEnabled: true,
bevelThickness: 0.7,
bevelSize: .7,
bevelSegments: 2
});
font: fontLoader를 통해 얻어온 폰트 객체
size: 텍스트 mesh의 크기(기본값 100)
height: 깊이 값(기본값 50)
curveSegments: 하나의 커브를 구성하는 정점의 개수(기본값 12)
bevelEnabled: 베벨링 처리를 할것인지 여부(기본값 true)
bevelThickness: 베벨링에 대한 두께(기본값 6)
bevelSize: shape의 외곽선으로부터 얼마나 멀리 베벨링할 것인지에 대한 거리값(기본값 2)
bevelSegment: 베벨링 단계수(기본값 3)