GIS Developer λμ Three.js κ°μ’ : https://www.youtube.com/watch?v=ZGACJosABBw
νκΈ°μ© κΉνλΈ : https://github.com/sduu/three-tutorial
κ°λ° νκ²½ ꡬμ±
1. Visual Studio Code μ€μΉ
https://code.visualstudio.com/
2. Three.js λΌμ΄λΈλ¬λ¦¬ μ€μΉ
: μ€μ΅μ module λ°©μμΌλ‘ κ°λ°νκΈ°λλ¬Έμ three.module.js νμΌμ μ¬μ©νλ€.
3. μ€μ΅μ μ§νν html νμΌμ μμ±
4. νμ΄μ§ μ€νμ μν΄ μ€μ νμΌμ μμ±
- VSCode μ€ν λ° λλ²κ·Έλ₯Ό μ ν (ctrl + shift + D)
- launch.json νμΌ λ§λ€κΈ°λ₯Ό μ ν
- νμ΄μ§λ₯Ό μ΄λ€ μΉλΈλΌμ°μ μ νμν κ²μΈμ§ μ ν
- μ€νμ μν μ€μ νμΌμ΄ μμ±λ¨
- μ€ν λ©λ΄μμ λλ²κΉ μμμ ν΄λ¦νλ©΄ νμ΄μ§κ° μΉλΈλΌμ°μ μ νμλ¨ (F5)
5. Visual Studio Code μ νμ₯νλ‘κ·Έλ¨μΈ Live Server μ€μΉ
: https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
: μΉκ°λ°μ μν΄μ μΉνμ΄μ§κ° μΉμλ²λ₯Ό ν΅ν΄ μ κ·Όν μ μλλ‘ μ€μ νκΈ° μν¨
(νμ¬λ λ‘컬 μ£Όμλ‘ νμ΄μ§μ μ κ·Όνκ³ μμ§λ§ λΌμ΄λΈμλ²λ₯Ό ν΅ν΄ μ£Όμλ₯Ό url ννλ‘ μ κ·Όν μ μμ)
: μ€νν νμ΄μ§λ₯Ό μ ν ν νλ¨μ go live λ²νΌμ ν΄λ¦ (alt + L, O)
κΈ°λ³Έ κ΅¬μ± μμμ μ½λ
Three.jsμ ꡬμ±
: Three.js λ 3μ°¨μ κ°μ²΄λ‘ ꡬμ±λλ μ₯λ©΄(Scene)μ΄ μκ³ ,
μ΄ μ₯λ©΄μ λͺ¨λν°μ κ°μ μΆλ ₯ μ₯μΉμ μΆλ ₯ν μ μλ λ λλ¬(Renderer)κ° μλ€.
: μ₯λ©΄μ λ λλ§ν λλ μ΄λ€ μμ μμ μ₯λ©΄μ 보λμ§μ λ°λΌ λ€λ₯΄κ² λ λλ§ λλλ°
κ·Έ μμ μ μΉ΄λ©λΌ(Camera)λ‘ μ μνλ€.
: μ₯λ©΄μ μ‘°λͺ (Light)κ³Ό 3μ°¨μ λͺ¨λΈμΈ Meshλ‘ κ΅¬μ±λλ€.
3μ°¨μ νμμ΄ νλ©΄μ νμλκΈ° μν΄μλ μ μ ν κ΄μμ΄ νμνκΈ° λλ¬Έμ μ‘°λͺ μ΄ μλκ²μ΄λ€.
: Meshλ Object3Dμ νμ ν΄λμ€μΈλ°
νμ λ±μ μ μνλ Geometry μ μμ λ° ν¬λͺ λ λ±μ μ μνλ Material λ‘ μ μλλ€.
νμ νλ μ μ‘면체
<!-- 01-basic.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="01-basic.css">
<!--
* type="module" : three.js λΌμ΄λΈλ¬λ¦¬λ₯Ό module λ²μ μΌλ‘ import νκΈ° μν΄ μλ°μ€ν¬λ¦½νΈ νμΌμ module νμ
μΌλ‘ μΆκ°
* defer : μ΄ μμ±μ μ§μ νλ©΄ νμ΄μ§κ° λͺ¨λ λ‘λ© λ ν μλ°μ€ν¬λ¦½νΈκ° μ€ν λ¨
-->
<script type="module" src="01-basic.js" defer></script>
</head>
<body>
<div id="webgl-container"></div>
</body>
</html>
/* 01-basic.css */
* {
outline: none;
margin: 0;
}
body {
overflow: hidden;
}
#webgl-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
// 01-basic.js
import * as THREE from '../build/three.module.js';
class App {
constructor() {
const divContainer = document.querySelector('#webgl-container');
/* λ€λ₯Έ method μμ μ°Έμ‘° ν μ μλλ‘ field ν */
this._divContainer = divContainer;
/* antialias : μ€λΈμ νΈλ€μ κ²½κ³μ μ΄ κ³λ¨ νμ μμ΄ λΆλλ½κ² ννλλ μ΅μ
*/
const renderer = new THREE.WebGLRenderer({antialias: true});
/* pixel ratio : ν½μ
λ°λ μ€μ */
renderer.setPixelRatio(window.devicePixelRatio);
/* renderer.domElement : canvas νμ
μ Dom κ°μ²΄ */
divContainer.appendChild(renderer.domElement);
this._renderer = renderer;
const scene = new THREE.Scene();
this._scene = scene;
/* λ°μ€λ‘ μμνλ field μ methodλ App ν΄λμ€ λ΄λΆμμλ§ μ¬μ©λλ€λ μλ―Έλ‘ μ.
javascriptμμλ private μ±κ²©μ λΆμ¬ν μ μλ κΈ°λ₯μ΄ μκΈ° λλ¬Έμ μ΄μ κ°μ΄ λ°μ€λ‘ νννλκ²μ΄ κ°λ°μκ°μ μ½μμ΄λ€) */
this._setupCamera();
this._setupLight();
this._setupModel();
/* renderer λ camera λ μ°½ν¬κΈ°κ° λ³κ²½ λ λ λ§λ€ ν¬κΈ°μ λ§κ² μμ± κ°μ μ¬μ€μ ν΄μ£Όμ΄μΌ ν¨ */
/* resize methodλ₯Ό bind ν΅ν΄ λκΈ°λ μ΄μ : resize method μμμ this κ° κ°λ₯΄ν€λ κ°μ²΄κ° μ΄λ²€νΈ κ°μ²΄κ° μλ App ν΄λμ€μ κ°μ²΄κ° λλλ‘ νκΈ° μν¨ */
window.onresize = this.resize.bind(this);
/* μμ±μμμ 무쑰건 ν λ²μ νΈμΆ : μ°½ν¬κΈ°μ λ§κ² μ€μ */
this.resize();
requestAnimationFrame(this.render.bind(this));
}
_setupCamera() {
/* 3μ°¨μ κ·Έλν½μ μΆλ ₯ν μμμ λν ν¬κΈ°λ₯Ό κ°μ Έμ΄ */
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);
}
/* νλμ μ μ‘면체 meshλ₯Ό μμ±νλ method */
_setupModel() {
/* νν : BoxGeometry(κ°λ‘, μΈλ‘, κΉμ΄) */
const geometry = new THREE.BoxGeometry(1, 1, 1);
/* μ¬μ§ */
const material = new THREE.MeshPhongMaterial({color: 0x44a88});
/* mesh μμ± */
const cube = new THREE.Mesh(geometry, material);
/* scene κ°μ²΄μ ꡬμ±μμλ‘ μΆκ° */
this._scene.add(cube);
this._cube = cube;
}
resize() {
const width = this._divContainer.clientWidth;
const height = this._divContainer.clientHeight;
/* camera μμ± λ³κ²½ */
this._camera.aspect = width / height;
this._camera.updateProjectionMatrix();
/* renderer μ ν¬κΈ° μ€μ */
this._renderer.setSize(width, height);
}
/* time : requestAnimationFrame κ° render ν¨μμ μ λ¬ν΄μ£Όλ κ° */
render(time) {
/* renderer κ° scene μ μΉ΄λ©λΌ μμ μΌλ‘ λ λλ§νλλ‘ ν¨ */
this._renderer.render(this._scene, this._camera);
/* time μΈμ : λ λλ§μ΄ μ²μ μμλ μ΄ν κ²½κ³Όλ μκ°κ°. millisecond unit */
this.update(time);
/* μμ±μ μ½λμ λμΌ */
requestAnimationFrame(this.render.bind(this));
}
update(time) {
time *= 0.001; // second unit
/* μ μ‘면체μ νμ κ°μ time κ°μ μ§μ */
this._cube.rotation.x = time;
this._cube.rotation.y = time;
}
}
window.onload = function() {
new App();
}