๐ผ๋๋ฃ๐ผ๋ถ์ ๋์์ผ๋ก inflearn three.js๋ก ์์ํ๋ 3D ์ธํฐ๋ํฐ๋ธ ์น ์ ์๊ฐํ ์ ์๊ฒ๋์๋ค.
three.js ์์ ๋ฌด์ธ๊ฐ๋ฅผ ๊ทธ๋ฆฌ๋ ค๋ฉด scene, camera, renderer ๊ฐ ํ์ํจ
<body>
<canvas id="three-canvas"></canvas>
</body>
import * as THREE from 'three';
const canvas = document.querySelector('#three-canvas');
if (canvas) {
const renderer = new THREE.WebGLRenderer({
canvas,
antialias: true, // true: ๋ถ๋๋ฝ๊ฒ ํํ (๊ณ๋จ์์ผ๋ก ํ
๋๋ฆฌ๊ฐ ๋์ด์๊ฑฐ๋ ํ๋ ๋ถ๋ถ)
});
}
// renderer ์ฌ์ด์ฆ ์ค์
renderer.setSize(window.innerWidth, window.innerHeight);
const scene = new THREE.Scene();
// PerspectiveCamera, ์๊ทผ ์นด๋ฉ๋ผ (๊ธฐ๋ณธ๊ฐ x=0, y=0, z=0)
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1);
camera.position.y = 2;
camera.position.z = 8; // ๊ทธ๋ฆด ๋์์ ๊ฐ๋
์ ์ธ ๊ฑฐ๋ฆฌ์ ๊ฐ
scene.add(camera);
// BoxGeometry(width, height, depth) - ํํ
const geometry = new THREE.BoxGeometry(1, 1, 1);
// ์์น ํด์ฃผ๊ธฐ (hex ๋ ์ฌ์ฉ ๊ฐ๋ฅ) - ์ฌ์ง
const material = new THREE.MeshBasicMaterial({color: 'red',});
// ํํ์ ์ฌ์ง์ ๊ฐ์ง ๋ฌผ์ฒด ์์ฑ
const mesh = new THREE.Mesh(geometry, material);
// ๋ฌด๋์ ๋ฌผ์ฒด ๋ถ์ฐฉ
scene.add(mesh);
renderer.render(scene, camera);
// window resize event ์ ์๋์ฝ๋ ์ํ๋๋๋ก ์ฒ๋ฆฌ
// ๋ฐฐ๊ฒฝ ํฌ๊ธฐ์ ๋ฐ๋ผ ๋ฌผ์ฒด ํฌ๊ธฐ๊ฐ ๋ณ๊ฒฝ๋์ง ์๋๋ก ํ๋ ฌ ๊ตฌ์กฐ๋ฅผ ๋ค์ ๊ณ์ฐํ๊ฒ ํจ
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
// ์ฐฝ ํฌ๊ธฐ์ ๋ฐ๋ผ ๋ฐฐ๊ฒฝ ์ฌ์ด์ฆ ๋ณ๊ฒฝ
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.render(scene, camera);
const renderer = new THREE.WebGLRenderer({
canvas,
antialias: true,
alpha: true, // ๋ฐฐ๊ฒฝ์ ํฌ๋ช
ํ๊ฒ
});
renderer.setSize(window.innerWidth, window.innerHeight);
// ํ์ํ ์ฌ์ด์ฆ์ ๋ ๋ฐฐ ๋งํผ์ผ๋ก ํฌ๊ธฐ (width/height) ๋ฅผ ์ค์ ํ์ฌ ๊ณ ํด์๋๋ก ํํ
renderer.setPixelRatio(2);
// ๋ฐฐ๊ฒฝ์ ์ค์
renderer.setClearColor('#00ff00');
// ๋ฐฐ๊ฒฝ ํฌ๋ช
๋ ์กฐ์
renderer.setClearAlpha(0.1);
const scene = new THREE.Scene();
scene.background = new THREE.Color('blue')
const light = new THREE.DirectionalLight(0xffffff, 0.5);
// ๋น์ ๋ฐฉํฅ
light.position.x = 1;
light.position.z = 2;
scene.add(light);
function draw(): void {
// ๊ฐ๋ก๋ก ํ์
mesh.rotation.y += 3;
renderer.render(scene, camera);
requestAnimationFrame(draw);
draw();
}
- autoStart- ์๋์ผ๋ก ์๊ณ๋ฅผ ์์์ํฌ์ง ์ฌ๋ถ (๊ธฐ๋ณธ๊ฐ true)
- property
- startTime:Float - ์๊ณ์ start ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉด ์๊ฐ์ ๋ฉ์ถค
- oldTime:Float - ์๊ณ์ start/getElapsedTime/getDelta ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉด ์๊ฐ์ ๋ฉ์ถค
- startTime:Float - ์๊ณ์ start ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉด ์๊ฐ์ ๋ฉ์ถค
- elapsedTime - ์๊ณ๊ฐ ์๋ํ ์ด ์๊ฐ
- method
- start(): void - ์๊ณ๋ฅผ ์์, startTime & oldTime์ ํ์ฌ ์๊ฐ์ผ๋ก ์ ๋ฐ์ดํธ, elapsedTime ์ 0ใ ์ผ๋ก ์ค์
- stop(): void - ์๊ณ๋ฅผ ๋ฉ์ถ๊ณ oldTime์ ํ์ฌ ์๊ฐ์ผ๋ก ์ค์
- getElapsedTime(): Float - ์๊ณ๊ฐ ์์ํ ์ดํ๋ก๋ถํฐ์ ์ด๋ฅผ ๊ฐ์ ธ์ค๋ฉฐ oldTime์ ํ์ฌ ์๊ฐ์ผ๋ก ์ค์
- getDelta(): Float - oldTime์ด ์ค์ ๋ ์ดํ๋ก๋ถํฐ ์ง๋ ์ด๋ฅผ ๊ฐ์ ธ์ค๋ฉฐ oldTime์ ํ์ฌ ์๊ฐ์ผ๋ก ์ค์
getElapsedTime ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
const clock = new THREE.Clock();
function draw(): void {
const time = clock.getElapsedTime();
mesh.rotation.y = 2 * time; // ์๋๋ฅผ ๋ ๋น ๋ฅด๊ฒ ํ๊ณ ์ถ์ผ๋ฉด 2๋ณด๋ค ํฐ ๊ฐ์ ์ฌ์ฉ
renderer.render(scene, camera);
requestAnimationFrame(draw);
}
draw();
getDelta ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
const clock = new THREE.Clock();
function draw(): void {
const delta = clock.getDelta();
mesh.rotation.y += 3 * delta;
renderer.render(scene, camera);
requestAnimationFrame(draw);
}
draw();
๋ง์ฝ draw ๋ด์์ ๊ฐ์ clock ์ getDelta ์ getElapsedTime ๋ฅผ ๋ ๋ค ์ฌ์ฉํ ๊ฒฝ์ฐ ๋์์ด ๊ผฌ์ผ ์ ์๋ค. (๊ฐ ๋ฉ์๋ ํธ์ถ ์ oldTime ์ ์ด๊ธฐํํ๋๋ฐ ์ด๋ถ๋ถ ๋๋ฌธ์ผ ๋ฏ?)
npm i gsap
import gsap from 'gsap';
//...
function draw(): void {
renderer.render(scene, camera);
renderer.requestAnimationFrame(draw);
}
// mesh์ y์์น๋ฅผ 2๊น์ง 1์ด ๋์ ์ด๋ํ๋ค.
gasp.to(mesh.position, {
duration: 1,
y: 2,
});
draw();
const scene = new THREE.Scene();
// ๋ค์์๋ ๋ฐ์ค๋ ์๊ฐ์ ๋ฎ์ธ ์์ผ๋ก ๋ณด์
scene.fog = new THREE.Fog('black', 3, 7);