SeemsPyo 5 years ago
parent
commit
de3432855e

+ 4 - 6
threejs/lessons/kr/langinfo.hanson

@@ -1,17 +1,15 @@
 {
   language: '한국어',
   langCode: 'ko',
-  defaultExampleCaption: "새 에서 보기",
+  defaultExampleCaption: "새 에서 보기",
   title: 'Three.js 튜토리얼',
   description: 'Three.js 입문자를 위한 튜토리얼',
   link: 'http://threejsfundamentals.org/',
   commentSectionHeader: `
     <div>
-      <a href="http://stackoverflow.com/questions/tagged/three.js">스택오버플로우 바로가기</a>
-    </div>
-
-    <div>
-      <a href="http://github.com/greggman/threefundamentals/issues">깃허브에 이슈 남기기</a>
+      <a href="http://stackoverflow.com/questions/tagged/three.js">Stackoverflow</a>
+      /
+      <a href="http://github.com/greggman/threefundamentals/issues">Github</a>
     </div>
   `,
   missing: `

+ 118 - 132
threejs/lessons/kr/threejs-fundamentals.md

@@ -38,44 +38,44 @@ Three.js는 3차원 세계를 다루므로, 우리는 정육면체(cube)를 3차
   `Scene`과 `Camera` 객체를 넘겨 받아 카메라의 [*절두체(frustum)*](https://ko.wikipedia.org/wiki/%EC%A0%88%EB%91%90%EC%B2%B4)
   안 3D 장면의 일부를 평면(2차원) 이미지로 렌더링합니다.
 
-* [씬 그래프(Scene graph)](threejs-scenegraph.html)는 `Scene` 객체 또는
-  다수의 `Mesh`, `Light`, `Group`, `Object3D`, `Camera` 객체로 이루어진
-  트리 구조와 유사합니다. `Scene` 객체는 씬 그래프의 최상위 노드로서 배경색(background color),
-  안개(fog) 등의 요소를 포함합니다. `Scene` 객체에 포함된 객체들 또한 부모/자식의
+* [씬 그래프(Scene graph)](threejs-scenegraph.html)는 `Scene` 또는
+  다수의 `Mesh`, `Light`, `Group`, `Object3D`, `Camera`로 이루어진
+  트리 구조와 유사합니다. `Scene` 씬 그래프의 최상위 노드로서 배경색(background color),
+  안개(fog) 등의 요소를 포함합니다. `Scene`에 포함된 객체들 또한 부모/자식의
   트리 구조로 이루어지며, 이는 각 객체의 유래와 방향성을 나타냅니다. 쉽게 말해 자식 객체의
-  위치(position)와 방향(orientation)은 부모를 기준으로 한다는 거죠. 예를 들어 자동차의 바퀴가
+  위치(position)와 방향(orientation)이 부모 기준이라는 거죠. 예를 들어 자동차의 바퀴가
   자동차 객체의 자식 객체라면, 자동차 객체의 방향을 움직일 때, 바퀴 객체의 방향 또한 같이
   움직입니다(더 자세한 내용은 [씬 그래프에 관한 글](threejs-scenegraph.html)에서 확인할 수 있습니다)
 
-  `Camera` 객체가 도표에서 반쯤 나간 것이 보이나요? 이는 의도된 것으로, 다른 객체와 달리
-  `Camera` 객체는 굳이 씬 그래프에 포함될 필요가 없음을 보여주기 위함입니다. 물론 다른
-  객체와 마찬가지로 `Camera` 객체 또한 다른 객체의 자식 객체가 될 수 있습니다. 이러면
-  부모 객체에 따라 `Camera` 객체 또한 움직이겠죠. [씬 그래프에 관한 글](threejs-scenegraph.html)
-  마지막에 여러개의 `Camera` 객체를 넣는 예제가 있으니 참고하시기 바랍니다.
-
-* `Mesh`는 어떤 `Material` 객체로 하나의 `Geometry` 객체를 그리는 객체입니다.
-  `Material`, `Geometry` 객체는 재사용이 가능하여 여러개의 `Mesh` 객체가 하나의
-  `Material` 또는 `Geometry` 객체를 동시에 참조할 수 있습니다. 파란색 정육면체 2개를
-  그린다고 해보죠. 일단 두 정육면체의 위치가 달라야 하니, 2개의 `Mesh` 객체
-  필요합니다. 그리고 정점(vertext, 꼭지점) 데이터를 가진 한 개의 `Geometry` 객체
-  채색을 위한 하나의 `Material` 객체가 필요하겠죠. 각 `Mesh` 객체는 객체를 복사할 필요
-  없이, 같은 `Geometry` 그리고 `Material`를 참조할 수 있습니다.
-
-* `Geometry` 객체는 기하학 객체의 정점 데이터입니다. 구(sphere), 정육면체(cube),
+  `Camera`가 도표에서 반쯤 나간 것이 보이나요? 이는 의도된 것으로, 다른 객체와 달리
+  `Camera`는 굳이 씬 그래프에 포함될 필요가 없음을 보여주기 위함입니다. 물론 다른
+  객체와 마찬가지로 `Camera` 또한 다른 객체의 자식 객체가 될 수 있습니다. 이러면
+  부모 객체에 따라 `Camera` 또한 움직이겠죠. [씬 그래프에 관한 글](threejs-scenegraph.html)
+  마지막에 여러개의 `Camera`를 넣는 예제가 있으니 참고하시기 바랍니다.
+
+* `Mesh`는 어떤 `Material`로 하나의 `Geometry`를 그리는 객체입니다.
+  `Material`, `Geometry`는 재사용이 가능하여 여러개의 `Mesh`가 하나의
+  `Material` 또는 `Geometry`를 동시에 참조할 수 있습니다. 파란색 정육면체 2개를
+  그린다고 해보죠. 일단 두 정육면체의 위치가 달라야 하니, 2개의 `Mesh`가
+  필요합니다. 그리고 정점(vertext, 꼭지점) 데이터를 가진 한 개의 `Geometry`와
+  채색을 위한 하나의 `Material`이 필요하겠죠. 이때 각 `Mesh`는 객체를 복사할
+  필요 없이, 같은 `Geometry` 그리고 `Material`을 참조할 수 있습니다.
+
+* `Geometry`는 기하학 객체의 정점 데이터입니다. 구(sphere), 정육면체(cube),
   면(plane), 개, 고양이, 사람, 나무, 건물 등 아주 다양한 것이 될 수 있죠. Three.js는
   기본적으로 몇 가지의 내장(built-in) [기하학 객체](threejs-primitives.html)를 제공합니다.
   물론 [직접 기하학 객체를 만들](threejs-custom-geometry.html) 수도 있고,
   [파일에서 기하학 객체를 불러올](threejs-load-obj.html) 수도 있죠.
 
-* `Material` 객체는 기하학 객체를 그리는 데 사용하는 [표면 속성](threejs-materials.html)입니다.
-  색이나 밝기 등을 지정할 수 있죠. 하나의 `Material` 객체는 여러개의 `Texture` 객체를 사용할 수
+* `Material` 기하학 객체를 그리는 데 사용하는 [표면 속성](threejs-materials.html)입니다.
+  색이나 밝기 등을 지정할 수 있죠. 하나의 `Material`는 여러개의 `Texture`를 사용할 수
   있습니다. 기하학 객체의 표면을 이미지로 덮어씌울 때 주로 사용하죠.
 
-* `Texture` 객체는 이미지나 [파일에서 로드한 이미지](threejs-textures.html),
+* `Texture`는 이미지나 [파일에서 로드한 이미지](threejs-textures.html),
   [canvas로 생성한 이미지](threejs-canvas-textures.html)
   또는 [다른 `Scene` 객체에서 렌더링한 결과물](threejs-rendertargets.html)에 해당합니다.
 
-* `Light` 객체는 [여러 종류의 광원에 해당](threejs-lights.html)합니다.
+* `Light`는 [여러 종류의 광원에 해당](threejs-lights.html)합니다.
 
 이제 기본적인 구조에 대해 배웠으니 아래와 같은 구조의 *"Hello Cube"*를 만들어 봅시다.
 
@@ -144,7 +144,7 @@ const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
 설정했습니다. 알아둬야 할 건 Three.js의 대부분이 각도 단위로 호도(radians)를
 사용하는데, 원근 카메라만 특이하게 도(degrees)를 인자로 받는다는 점입니다.
 
-`aspect` canvas의 가로 세로 비율입니다. 이는 [다른 글](threejs-responsive.html)
+`aspect` canvas의 가로 세로 비율입니다. 이는 [다른 글](threejs-responsive.html)
 에서 자세히 다루겠지만, 기본 설정으로 canvas의 크기는 300x150이니 비율도
 300/150, 2로 설정했습니다.
 
@@ -170,28 +170,27 @@ const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
 camera.position.z = 2;
 ```
 
-우리가 원하는 결과물은 다음과 같습니다.
+우리가 원하는 결과물을 다음처럼 그려볼 수 있습니다.
 
 <img src="resources/scene-down.svg" width="500" class="threejs_center"/>
 
-In the diagram above we can see our camera is at `z = 2`. It's looking
-down the -Z axis. Our frustum starts 0.1 units from the front of the camera
-and goes to 5 units in front of the camera. Because in this diagram we are looking down,
-the field of view is affected by the aspect. Our canvas is twice as wide
-as it is tall so across view the field of view will be much wider than
-our specified 75 degrees which is the vertical field of view.
+카메라는 `z = 2` 위치에서 -Z 방향을 바라봅니다. 절두체는 카메라 앞 0.1 칸에서
+5칸까지를 차지하죠. 또한 아래를 바라보는 형태이기 때문에, 시야각은 canvas
+크기의 영향을 받습니다. 앞서 만든 canvas는 두 배 더 크기 때문에 실제로는 시야각이
+위에서 정의한 75도 보다는 훨씬 넓을 것입니다.
 
-Next we make a `Scene`. A `Scene` in three.js is the root of a form of scene graph.
-Anything you want three.js to draw needs to be added to the scene. We'll
-cover more details of [how scenes work in a future article](threejs-scenegraph.html).
+이제 `Scene`을 만듭니다. Three.js에서 `Scene`이란 씬 그래프에서 가장 상단에
+위치한 요소입니다. 뭔가를 화면에 렌더링하고 싶다면 먼저 `Scene`에 추가해야 하죠.
+여기서는 간단하게 다룰 것이므로 자세한 내용은 [이 글](threejs-scenegraph.html)을
+참고하세요.
 
 ```js
 const scene = new THREE.Scene();
 ```
 
-Next up we create a `BoxGeometry` which contains the data for a box.
-Almost anything we want to display in Three.js needs geometry which defines
-the vertices that make up our 3D object.
+다음으로 간단한 정육면체를 만들어보죠. Three.js에서 렌더링되는 대부분의 3D 요소는
+정점 데이터가 정의된 기하학 객체를 필요로 합니다. 지금은 정육면체를 만들어야 하니
+`BoxGeometry` 생성자를 호출하겠습니다.
 
 ```js
 const boxWidth = 1;
@@ -200,49 +199,44 @@ const boxDepth = 1;
 const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
 ```
 
-We then create a basic material and set its color. Colors can
-be specified using standard CSS style 6 digit hex color values.
+다음으로 `Material`을 만들고 색을 지정합니다. 색을 지정할 때는 CSS처럼
+숫자 형태의 hex 코드를 이용합니다(`#` 대신 `0x`. 역주).
 
 ```js
 const material = new THREE.MeshBasicMaterial({color: 0x44aa88});
 ```
 
-We then create a `Mesh`. A `Mesh` in three represents the combination
-of a `Geometry` (the shape of the object) and a `Material` (how to draw
-the object, shiny or flat, what color, what texture(s) to apply. Etc.)
-as well as the position, orientation, and scale of that
-object in the scene.
+그리고 앞서 만든 `Geometry`(물체의 형태)와 `Material`(물체의 색, 밝기, 질감 등)을
+이용해 `Mesh`를 만듭니다. `Mesh`는 `Geometry`, `Material` 외에도 물체의 위치, 방향,
+크기 등을 담은 객체입니다.
 
 ```js
 const cube = new THREE.Mesh(geometry, material);
 ```
 
-And finally we add that mesh to the scene
+마지막으로 완성된 정육면체 `Mesh`를 `Scene`에 넣어줍니다.
 
 ```js
 scene.add(cube);
 ```
 
-We can then render the scene by calling the renderer's render function
-and passing it the scene and the camera
+`renderer`의 `render` 메서드에 `Scene`과 `Camera`를 넘겨주면 화면을 렌더링할
+수 있습니다.
 
 ```js
 renderer.render(scene, camera);
 ```
 
-Here's a working example
+아래는 전체 코드입니다.
 
 {{{example url="../threejs-fundamentals.html" }}}
 
-It's kind of hard to tell that is a 3D cube since we're viewing
-it directly down the -Z axis and the cube itself is axis aligned
-so we're only seeing a single face.
-
-Let's animate it spinning and hopefully that will make
-it clear it's being drawn in 3D. To animate it we'll render inside a render loop using
-[`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame).
+물론 위 예제는 3D 정육면체라고 하긴 어렵습니다. 코드 상으로 Three.js는
+분명 3D 정육면체를 그렸지만, 카메라가 -Z 방향을 바라보고, 정육면체도
+Z 축에 맞추어 정렬되어 있기 때문에 한 면만 보입니다.
 
-Here's our loop
+한 번 이 물체에 애니메이션을 주고 3D처럼 보이는지 확인해보죠.
+애니메이션을 구현하기 위해 [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) 루프 안에서 렌더링 함수를 호출합니다.
 
 ```js
 function render(time) {
@@ -258,31 +252,31 @@ function render(time) {
 requestAnimationFrame(render);
 ```
 
-`requestAnimationFrame` is a request to the browser that you want to animate something.
-You pass it a function to be called. In our case that function is `render`. The browser
-will call your function and if you update anything related to the display of the
-page the browser will re-render the page. In our case we are calling three's
-`renderer.render` function which will draw our scene.
+`requestAnimationFrame`은 브라우저에 애니메이션 프레임을 요청하는 함수입니다.
+인자로 실행할 함수를 전달하면 되죠(이 경우는 `render` 함수). 브라우저는 넘겨받은
+함수를 실행하고, 페이지에 변화가 있다면 페이지를 다시 렌더링합니다. 위 예제에서는
+Three.js의 `renderer.render` 메서드를 호출해 씬을 렌더링하도록 했죠.
 
-`requestAnimationFrame` passes the time since the page loaded to
-our function. That time is passed in milliseconds. I find it's much
-easier to work with seconds so here we're converting that to seconds.
+`requestAnimationFrame`은 매개변수로 넘겨받은 함수에 페이지가 로드된 이후의 시간값을
+밀리초 단위로 넘겨줍니다. 전 초 단위가 더 익숙하기 때문에, 밀리초 단위를 초 단위로
+변경하였습니다.
 
-We then set the cube's X and Y rotation to the current time. These rotations
-are in [radians](https://en.wikipedia.org/wiki/Radian). There are 2 pi radians
-in a circle so our cube should turn around once on each axis in about 6.28
-seconds.
+그리고 정육면체의 X, Y축 회전값을 현재 시간값으로 설정합니다(이 회전값은 [라디안(radians)](https://ko.wikipedia.org/wiki/%EB%9D%BC%EB%94%94%EC%95%88)
+단위를 사용합니다). 360˚도는 2π 라디안이니 큐브는 각 축마다
+약 6.28초에 한 바퀴를 돌게 됩니다.
 
-We then render the scene and request another animation frame to continue
-our loop.
+그리고 씬을 렌더링 한 후, 브라우저에 재귀적으로 애니메이션 프레임을 요청해 이
+애니메이션이 반복되도록 합니다.
 
-Outside the loop we call `requestAnimationFrame` one time to start the loop.
+마지막으로 루프 바깥에서 `requestAnimationFrame`을 한 번 호출해 루프를
+시작합니다.
 
 {{{example url="../threejs-fundamentals-with-animation.html" }}}
 
-It's a little better but it's still hard to see the 3d. What would help is to
-add some lighting so let's add a light. There are many kinds of lights in
-three.js which we'll go over in [a future article](threejs-lights.html). For now let's create a directional light.
+아까보단 낫지만 아직 3D 물체라고 부르기엔 뭔가 부족합니다. 광원을 추가해 그림자가
+지도록 하면 어떨까요? 나중에 [이 글](threejs-lights.html)에서 자세히 다루겠지만,
+Three.js에는 다양한 종류의 광원이 있습니다. 다 살펴보기 힘드니 지금은 예시로
+`DirectionalLight`를 사용해보도록 하죠.
 
 ```js
 {
@@ -294,38 +288,37 @@ three.js which we'll go over in [a future article](threejs-lights.html). For now
 }
 ```
 
-Directional lights have a position and a target. Both default to 0, 0, 0. In our
-case we're setting the light's position to -1, 2, 4 so it's slightly on the left,
-above, and behind our camera. The target is still 0, 0, 0 so it will shine
-toward the origin.
+`DirectionnalLight`에는 `위치(position)`와 `목표(target)` 속성이 있습니다.
+기본값은 `0, 0, 0` 이죠. 먼저 `position`을 `-1, 2, 4`로 설정해 카메라보다
+약간 동서쪽, Z축으로는 약간 위로 보냅니다. `target`은 기본값 `0, 0, 0` 그대로
+두어 공간의 중앙을 비추도록 합니다.
 
-We also need to change the material. The `MeshBasicMaterial` is not affected by
-lights. Let's change it to a `MeshPhongMaterial` which is affected by lights.
+그리고 `material`도 바꿔야 합니다. `MeshBasicMaterial`은 광원에 반응하지 않으니,
+광원에 반응하는 `MeshPhongMaterial`로 바꿉니다(`phong`은 광원 반사 모델을 처음 개발한 사람 이름. 역주).
 
 ```js
 -const material = new THREE.MeshBasicMaterial({color: 0x44aa88});  // greenish blue
 +const material = new THREE.MeshPhongMaterial({color: 0x44aa88});  // greenish blue
 ```
 
-Here is our new program structure
+다음은 현재까지의 프로그램 구조를 도식화 한 것이고,
 
 <div class="threejs_center"><img src="resources/images/threejs-1cube-with-directionallight.svg" style="width: 500px;"></div>
 
-And here it is working.
+아래는 결과물입니다.
 
 {{{example url="../threejs-fundamentals-with-light.html" }}}
 
-It should now be pretty clearly 3D.
+이제 3D라고 불러도 어색하지 않네요.
 
-Just for the fun of it let's add 2 more cubes.
+재미를 위해서 한 번 정육면체를 2개만 더 만들어 봅시다.
 
-We'll use the same geometry for each cube but make a different
-material so each cube can be a different color.
+미리 만들어 놨던 `Geometry`를 사용하고, `Material`만 바꿔 다른 색을
+가진 큐브 2개를 만들겠습니다.
 
-First we'll make a function that creates a new material
-with the specified color. Then it creates a mesh using
-the specified geometry and adds it to the scene and
-sets its X position.
+먼저 함수를 하나 만들어보겠습니다. 이 함수는 넘겨받은 색상값으로
+새로운 `Material`을 만들고, 넘겨받은 `Geometry`와 조합해 새로운
+`Mesh`를 만듭니다. 그리고 씬에 추가한 후 넘겨받은 X축 값을 통해 물체를 이동시키죠.
 
 ```js
 function makeInstance(geometry, color, x) {
@@ -340,8 +333,8 @@ function makeInstance(geometry, color, x) {
 }
 ```
 
-Then we'll call it 3 times with 3 different colors and X positions
-saving the `Mesh` instances in an array.
+다음으로 3가지 다른 색상과 X축 값으로 이 함수를 호출해 결과물을 배열로
+저장합니다.
 
 ```js
 const cubes = [
@@ -351,8 +344,8 @@ const cubes = [
 ];
 ```
 
-Finally we'll spin all 3 cubes in our render function. We
-compute a slightly different rotation for each one.
+마지막으로 `render` 함수에서 3개의 정육면체를 회전시킵니다. 동적인
+효과를 위해 각 큐브마다 약간 다른 값을 주도록 해보죠.
 
 ```js
 function render(time) {
@@ -368,34 +361,31 @@ function render(time) {
   ...
 ```
 
-and here's that.
+결과물은 다음과 같습니다.
 
 {{{example url="../threejs-fundamentals-3-cubes.html" }}}
 
-If you compare it to the top down diagram above you can see
-it matches our expectations. With cubes at X = -2 and X = +2
-they are partially outside our frustum. They are also
-somewhat exaggeratedly warped since the field of view
-across the canvas is so extreme.
+아까 위에서 좌표로 도식한 그림과 위 결과물을 비교해보면, 예상대로
+X축으로 -2, +2만큼 이동한 정육면체들의 일부가 절두체에서 약간 벗어났습니다.
+또한 가운데 정육면체에 비해 굉장히 굴절되어 보이는데, 이는 우리가 설정한 시야각이
+너무 좁은 탓입니다.
 
-Our program now has this structure
+위 프로그램은 구조는 다음과 같습니다.
 
 <div class="threejs_center"><img src="resources/images/threejs-3cubes-scene.svg" style="width: 610px;"></div>
 
-As you can see we have 3 `Mesh` objects each referencing the same `BoxGeometry`.
-Each `Mesh` references a unique `MeshPhongMaterial` so that each cube can have
-a different color.
+그림을 보면 각 `Mesh` 객체는 같은 `BoxGeometry`를 참조합니다. 그러나
+각 `Mesh`는 다른 `MeshPhongMaterial`을 참조하므로 다른 색을 띄죠.
 
-I hope this short intro helps to get things started. [Next up we'll cover
-making our code responsive so it is adaptable to multiple situations](threejs-responsive.html).
+이 인트로가 Three.js를 시작하는 데 도움이 되었으면 합니다.
+[다음 장에서는 코드를 반응형으로 만들어 다양한 상황에 적용할 수 있도록 해 볼 것입니다](threejs-responsive.html).
 
 <div id="es6" class="threejs_bottombar">
-<h3>es6 modules, three.js, and folder structure</h3>
-<p>As of version r106 the preferred way to use three.js is via <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">es6 modules</a>.</p>
+<h3>es6 모듈, Three.js, 프로젝트 구조</h3>
+<p>Three.js r106 릴리즈 이후에서는 three.js를 <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/import">es6 모듈</a>로 사용하길 권장합니다.</p>
 <p>
-es6 modules can be loaded via the <code>import</code> keyword in a script
-or inline via a <code>&lt;script type="module"&gt;</code> tag. Here's an example of
-both
+es6 모듈은 js 파일이나 인라인 <code>&lt;script type="module"&gt;</code> 태그 안에서
+<code>import</code> 키워드를 사용해 로드할 수 있습니다.
 </p>
 <pre class=prettyprint>
 &lt;script type="module"&gt;
@@ -406,13 +396,12 @@ import * as THREE from './resources/threejs/r115/build/three.module.js';
 &lt;/script&gt;
 </pre>
 <p>
-Paths must be absolute or relative. Relative paths always start with <code>./</code> or <code>../</code>
-which is different than other tags like <code>&lt;img&gt;</code> and <code>&lt;a&gt;</code>.
+경로는 절대경로나 상대경로를 사용해야 하며, 상대경로는 <code>&lt;img&gt;</code>, <code>&lt;a&gt;</code> 태그와
+달리 <code>./</code> 또는 <code>../</code>로 시작해야 합니다.
 </p>
 <p>
-References to the same script will only be loaded once as long as their absolute paths
-are exactly the same. For three.js this means it's required that you put all the examples
-libraries in the correct folder structure
+만약 절대경로가 같다면 같은 script는 한 번만 로드됩니다. Three.js 기반 프로젝트의 폴더 구조를
+잘 구성해야 하는 가장 큰 이유이죠.
 </p>
 <pre class="dos">
 someFolder
@@ -439,33 +428,30 @@ someFolder
      ...
 </pre>
 <p>
-The reason this folder structure is required is because the scripts in the
-examples like <a href="https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js"><code>OrbitControls.js</code></a>
-have hard coded relative paths like
+이유인 즉 <a href="https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js"><code>OrbitControls.js</code></a>
+같은 코드는 다음처럼 상대경로로 모듈을 로드하기 때문에
 </p>
 <pre class="prettyprint">
 import * as THREE from '../../../build/three.module.js';
 </pre>
 <p>
-Using the same structure assures then when you import both three and one of the example
-libraries they'll both reference the same three.module.js file.
+같은 폴더 구조를 사용함으로써 모든 예제 스크립트가 같은 three.module.js 파일을
+참조하도록 할 수 있죠.
 </p>
 <pre class="prettyprint">
 import * as THREE from './someFolder/build/three.module.js';
 import {OrbitControls} from './someFolder/examples/jsm/controls/OrbitControls.js';
 </pre>
-<p>This includes when using a CDN. Be sure your path to <code>three.modules.js</code> ends with
-<code>/build/three.modules.js</code>. For example</p>
+<p>아래는 CDN을 사용하는 예시입니다. <code>three.modules.js</code>의 경로가 <code>/build/three.modules.js</code>
+로 끝나야 한다는 것을 명심하세요.</p>
 <pre class="prettyprint">
 import * as THREE from 'https://unpkg.com/[email protected]/<b>build/three.module.js</b>';
 import {OrbitControls} from 'https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js';
 </pre>
-<p>If you'd prefer the old <code>&lt;script src="path/to/three.js"&gt;&lt;/script&gt;</code> style
-you can check out <a href="https://r105.threejsfundamentals.org">an older version of this site</a>.
-Three.js has a policy of not worrying about backward compatibility. They expect you to use a specific
-version, as in you're expected to download the code and put it in your project. When upgrading to a newer version
-you can read the <a href="https://github.com/mrdoob/three.js/wiki/Migration-Guide">migration guide</a> to
-see what you need to change. It would be too much work to maintain both an es6 module and a class script
-version of this site so going forward this site will only show es6 module style. As stated elsewhere,
-to support legacy browsers look into a <a href="https://babeljs.io">transpiler</a>.</p>
+<p>만약 여러분이 <code>&lt;script src="path/to/three.js"&gt;&lt;/script&gt;</code> 같은 스타일을 선호한다면,
+<a href="https://r105.threejsfundamentals.org">이 사이트의 이전 버젼을 확인해보시기 바랍니다</a>.
+Three.js에는 하위 호환성을 보장하는 정책이 있습니다. Three.js의 개발자들은 여러분이 특정 버젼을 골라서 쓸
+거라고 가정 하에 라이브러리를 개발하죠. 새 버젼으로 업그레이드할 때는 <a href="https://github.com/mrdoob/three.js/wiki/Migration-Guide">마이그레이션 가이드</a>를 참조해 바뀐 사항을 업데이트 하면 됩니다. es6 모듈과 스크립트
+버젼을 모두 다루기는 너무 버거우니 이 사이트에서는 es6 모듈 스타일만 사용할 것입니다. 개발자들이 늘상 추천하듯
+구형 브라우저를 지원하려면 바벨 등의 <a href="https://babeljs.io">트랜스파일러</a>를 찾아보기 바랍니다.</p>
 </div>

+ 271 - 0
threejs/lessons/kr/threejs-responsive.md

@@ -0,0 +1,271 @@
+Title: Three.js 반응형 디자인
+Description: Three.js 프로젝트를 반응형으로 만들기
+TOC: 반응형 디자인
+
+Three.js 두 번째 튜토리얼에 오신 것을 환영합니다!
+첫 번째 튜토리얼은 [Three.js의 기초](threejs-fundamentals.html)에 관한 내용이었죠.
+아직 이전 장을 보지 않았다면 이전 글을 먼저 읽어보길 추천합니다.
+
+이 장에서는 Three.js 앱을 어떤 환경에서든 구동할 수 있도록
+반응형으로 만드는 법에 대해 알아볼 것입니다. 웹에서 반응형이란
+웹 페이지를 PC, 타블렛, 스마트폰 등 다양한 환경에서 이용하기
+용이하도록 사이즈에 맞춰 콘텐츠를 최적화하는 것을 의미하죠.
+
+Three.js의 경우 일반 웹보다 고려해야할 요소가 많습니다.
+예를 들어 상하좌우에 컨트롤 패널이 있는 3D 에디터라든가,
+문서 사이에 들어가는 동적 그래프를 상상해볼 수 있죠.
+
+이전 글에서는 사이즈나 CSS 스타일을 정의하지 않은 canvas를 썼었죠.
+
+```html
+<canvas id="c"></canvas>
+```
+
+canvas 요소는 기본적으로 300x150 픽셀입니다.
+
+웹에서 어떤 요소의 크기를 지정할 때는 보통 CSS를 권장하죠.
+
+canvas가 페이지 전체를 차지하도록 CSS를 작성해봅시다.
+
+```html
+<style>
+html, body {
+   margin: 0;
+   height: 100%;
+}
+#c {
+   width: 100%;
+   height: 100%;
+   display: block;
+}
+</style>
+```
+
+body 요소는 기본적으로 5픽셀의 margin이 지정되어 있으니 `margin: 0`으로
+설정해 여백을 모두 없애줍니다. html과 body 요소의 높이를 지정하지 않으면
+컨텐츠의 높이만큼만 커지니, 높이를 100%로 맞춰 창 전체를 채우도록 합니다.
+
+그리고 `id=c`인 요소의 크기를 100%로 지정해 컨테이너, 이 예제에서는 body
+요소의 크기와 동일하게 맞춥니다.
+
+canvas 요소의 기본 `display` 속성은 `inline`입니다. `inline` 속성은 글자
+처럼 취급되어 흰 공백을 남길 수 있으니 `display` 속성을 `block`으로 지정합니다.
+
+아래는 이전 장에서 만든 예제에 방금 작성한 CSS 스타일을 덧붙인 것입니다.
+
+{{{example url="../threejs-responsive-no-resize.html" }}}
+
+canvas가 창 전체를 채우긴 했지만 문제가 좀 있네요. 정육면체가 창 크기에
+따라 늘어나 정육면체라기보다 너무 길거나 넓은 육면체처럼 보입니다. 예제를
+새 창에서 열어 창 크기를 조절해보세요. 정육면체가 어떻게 변하는지 확인할
+수 있을 겁니다.
+
+<img src="resources/images/resize-incorrect-aspect.png" width="407" class="threejs_center nobg">
+
+또 다른 문제는 저화질, 그러니까 깨지고 흐릿하게 보인다는 점입니다.
+창을 아주 크게 조절하면 문제를 바로 알 수 있을 거에요.
+
+<img src="resources/images/resize-low-res.png" class="threejs_center nobg">
+
+창 크기에 따라 늘어나는 문제부터 해결해봅시다. 먼저 카메라의 aspect(비율)
+속성을 canvas의 화면 크기에 맞춰야 합니다. 이는 canvas의 `clientWidth`와
+`clientHeight` 속성을 이용해 간단히 해결할 수 있죠.
+
+그리고 렌더링 함수를 다음처럼 수정합니다.
+
+```js
+function render(time) {
+  time *= 0.001;
+
++  const canvas = renderer.domElement;
++  camera.aspect = canvas.clientWidth / canvas.clientHeight;
++  camera.updateProjectionMatrix();
+
+  ...
+```
+
+이제 정육면체는 더이상 늘어나거나 찌그러들지 않을 겁니다.
+
+{{{example url="../threejs-responsive-update-camera.html" }}}
+
+예제를 새 창에서 열어 창 크기를 조절해보면, 정육면체의 비율이
+창 크기와 상관없이 그대로 유지되는 것을 확인할 수 있을 겁니다.
+
+<img src="resources/images/resize-correct-aspect.png" width="407" class="threejs_center nobg">
+
+이제 계단현상을 없애 봅시다.
+
+canvas 요소에는 두 종류의 크기값이 있습니다. 하나는 아까 CSS로
+설정한 canvas 요소의 크기이고, 다른 하나는 canvas 원본 픽셀 수에
+대한 값입니다. 예를 들어 128x64 픽셀인 이미지가 있다고 합시다.
+우리는 CSS를 이용해 이 이미지 요소를 400x200 픽셀로 보이도록 할 수
+있죠. canvas도 마찬가지입니다. 편의상 CSS로 지정한 크기를 디스플레이
+크기라고 부르겠습니다.
+
+```html
+<img src="128x64이미지.jpg" style="width:400px; height:200px">
+```
+
+canvas의 원본 크기, 해상도는 드로잉버퍼(drawingbuffer)라고 불립니다.
+Three.js에서는 `renderer.setSize` 메서드를 호출해 canvas의 드로잉버퍼
+크기를 지정할 수 있죠. 어떤 크기를 골라야 하냐구요? 당연히 "canvas의
+디스플레이 크기"죠! 다시 canvas의 `clientWidth`와 `clientHeight`를
+이용합시다.
+
+canvas의 원본 크기와 디스플레이 크기를 비교해 원본 크기를 변경할지 결정하는
+함수를 하나 만들어줍니다.
+
+```js
+function resizeRendererToDisplaySize(renderer) {
+  const canvas = renderer.domElement;
+  const width = canvas.clientWidth;
+  const height = canvas.clientHeight;
+  const needResize = canvas.width !== width || canvas.height !== height;
+  if (needResize) {
+    renderer.setSize(width, height, false);
+  }
+  return needResize;
+}
+```
+
+canvas를 리사이징할 필요가 있는지 검사했다는 점에 주의하세요.
+canvas 스펙상 리사이징은 화면을 다시 렌더링해야만 하므로, 같은
+사이즈일 때는 리사이징을 하지 않으므로써 불필요한 자원 낭비를
+막는 것이 좋습니다.
+
+canvas의 크기가 다르다면, `renderer.setSize` 메서드를 호출해
+새로운 width와 height를 넘겨줍니다. `renderer.setSize` 메서드는
+기본적으로 CSS의 크기를 설정하니 마지막 인자로 `false`를 넘겨주는
+것을 잊지 마세요. canvas가 다른 요소와 어울리려면 Three.js에서
+CSS를 제어하는 것 보다 다른 요소들처럼 CSS로 제어하는 것이 일관성
+있는 프로그래밍일 테니까요.
+
+위 함수는 canvas를 리사이징했으면 `true`를 반환합니다. 이 값을
+이용해 다른 요소들이 업데이트 해야 할지도 결정할 수 있겠네요.
+새로 만든 함수를 이용해 `render` 함수를 수정합시다.
+
+```js
+function render(time) {
+  time *= 0.001;
+
++  if (resizeRendererToDisplaySize(renderer)) {
++    const canvas = renderer.domElement;
++    camera.aspect = canvas.clientWidth / canvas.clientHeight;
++    camera.updateProjectionMatrix();
++  }
+
+  ...
+```
+
+canvas의 비율이 변하려면 canvas의 사이즈가 변해야 하므로,
+`resizeRendererToDisplaySize` 함수가 `true`를 반환했을 때만
+카메라의 비율을 변경합니다.
+
+{{{example url="../threejs-responsive.html" }}}
+
+이제 디스플레이 크기에 맞는 해상도로 렌더링될 겁니다.
+
+CSS가 디스플레이 크기를 제어하도록 해야 한다는 주장을 보충해보겠습니다.
+일단 이 코드를 [별도의 js 파일](../threejs-responsive.js)로 저장해주세요.
+아래의 예시들은 CSS가 디스플레이 크기를 제어하도록 한 예시입니다.
+잘 살펴보면 추가로 다른 코드를 써야할 필요가 없다는 걸 알 수 있죠.
+
+먼저 canvas를 텍스트 사이에 끼워 넣어보죠.
+
+{{{example url="../threejs-responsive-paragraph.html" startPane="html" }}}
+
+다음은 우측 컨트롤 패널 크기를 조정할 수 있는 에디터 형태의
+레이아웃에서 활용한 예시입니다.
+
+{{{example url="../threejs-responsive-editor.html" startPane="html" }}}
+
+HTML, CSS만 바뀌고 자바스크립트 코드는 한 줄도 바뀌지 않았습니다.
+
+## HD-DPI 디스플레이 다루기
+
+HD-DPI는 고해상도(high-density dot per inch)의 줄임말입니다.
+많은 Windows 기기나 맥, 스마트폰이 이 디스플레이를 사용하죠(스마트폰의
+실제 화면 크기가 데스크탑에 비해 훨씬 작지만, 해상도는 비슷한 경우를
+생각하면 됩니다. 한 픽셀을 선명하게 표현하기 위해 다수의 작은 픽셀을
+넣는 것. 역주).
+
+브라우저에서는 이에 대응하기 위해 픽셀의 집적도에 상관 없이
+CSS 픽셀을 이용해 요소의 크기를 지정합니다. 스마트폰이든,
+데스크탑이든 브라우저는 요소를 같은 크기로 좀 더 촘촘하게
+할 뿐이죠.
+
+Three.js로 HD-DPI를 다루는 방법은 아주 다양합니다.
+
+첫째는 아무것도 하지 않는 것입니다. 3D 렌더링은 많은 GPU 자원을
+소모하기 때문에 아마 가장 흔한 경우일 겁니다. 2018년의 이야기이긴
+하지만, 모바일 기기는 데스크탑에 비해 GPU 성능이 부족함에도 더 높은
+해상도를 가진 경우가 대부분입니다. 현재 플래그쉽 스마트폰은 HD-DPI
+약 3배의 해상도를 지녔습니다. 쉽게 말해 HD-DPI가 아닌 기기와 비교했을
+때 한 픽셀 당 픽셀 수가 1:9라는 것이고 이는 9배나 더 많은 렌더링
+작업을 처리해야 한다는 것을 의미하죠.
+
+9배 많은 픽셀을 처리하는 건 굉장히 까다로운 작업이지만, 만약 코드를
+저대로 내버려 둔다면 우리의 코드가 1픽셀을 계산할 때마다 브라우저는
+해당 픽셀보다 3배 큰 픽셀을 렌더링해야 합니다(3배 곱하기 3배 = 9배 많은 픽셀).
+
+이는 낮은 FPS, 즉 화면이 버벅거리게 만들 것이므로 무거운 Three.js
+앱을 만들 때는 지양해야 하는 요소이죠.
+
+물론 지양해야 한다는 건 기기의 해상도에 따라 화면을 렌더링할
+다른 방법들이 더 있다는 의미입니다.
+
+하나는 `rederer.setPixelRatio` 메서드를 이용해 해상도 배율을 알려주는
+것입니다. 브라우저로부터 CSS 픽셀과 실제 기기 픽셀의 배율을 받아
+Three.js에게 넘겨주는 것이죠.
+
+```js
+    renderer.setPixelRatio(window.devicePixelRatio);
+```
+
+그러면 `renderer.setSize`는 이제 알아서 사이즈에 배율을 곱해
+리사이징할 것입니다....만 **이 방법은 추천하지 않습니다**.
+
+다른 방법은 canvas를 리사이징할 때 직접 계산하는 것입니다.
+
+```js
+    function resizeRendererToDisplaySize(renderer) {
+      const canvas = renderer.domElement;
+      const pixelRatio = window.devicePixelRatio;
+      const width  = canvas.clientWidth  * pixelRatio | 0;
+      const height = canvas.clientHeight * pixelRatio | 0;
+      const needResize = canvas.width !== width || canvas.height !== height;
+      if (needResize) {
+        renderer.setSize(width, height, false);
+      }
+      return needResize;
+    }
+```
+
+객관적으로 따져봐도 이 방법이 훨씬 낫습니다. 이 방법으로는 개발자가
+원하는 결과가 나오니까요. Three.js로 앱을 만들 때 언제 canvas의
+드로잉버퍼 사이즈를 알아야 할지 특정하기란 어렵습니다. 예를 들어 전처리
+필터를 만든다거나, `gl_FragCoord`에 접근하는 쉐이더를 만든다거나,
+스크린샷을 찍는다거나, GPU가 관여하는 픽셀 수를 가져 온다거나, 
+
+
+This second way is objectively better. Why? Because it means I get what I ask for.
+There are many cases when using three.js where we need to know the actual
+size of the canvas's drawingBuffer. For example when making a post processing filter,
+or if we are making a shader that accesses `gl_FragCoord`, if we are making
+a screenshot, or reading pixels for GPU picking, for drawing into a 2D canvas,
+etc... There many many cases where if we use `setPixelRatio` then our actual size will be different
+than the size we requested and we'll have to guess when to use the size
+we asked for and when to use the size three.js is actually using.
+By doing it ourselves we always know the size being used is the size we requested.
+There is no special case where magic is happening behind the scenes.
+
+Here's an example using the code above.
+
+{{{example url="../threejs-responsive-hd-dpi.html" }}}
+
+It might be hard to see the difference but if you have an HD-DPI
+display and you compare this sample to those above you should
+notice the edges are more crisp.
+
+This article covered a very basic but fundamental topic. Next up lets quickly
+[go over the basic primitives that three.js provides](threejs-primitives.html).