Browse Source

chinese translation

chenlei 6 years ago
parent
commit
7c914be3df

+ 1 - 1
threejs/lessons/threejs-setup.md

@@ -1,7 +1,7 @@
 Title: Three.js Setup
 Description: How to setup your development environment for three.js
 
-This article is one in a series of articles about three.js.
+This article is one in a  series of articles about three.js.
 The first article was [about three.js fundamentals](threejs-fundamentals.html).
 If you haven't read that yet you might want to start there.
 

+ 15 - 0
threejs/lessons/zh_cn/index.md

@@ -0,0 +1,15 @@
+Title: Three.js基础
+
+帮助学习Three.js的系列文章.
+
+{{{include "threejs/lessons/toc.html"}}}
+
+
+<!--
+
+{{{table_of_contents}}}
+
+-->
+
+
+

+ 13 - 0
threejs/lessons/zh_cn/langinfo.hanson

@@ -0,0 +1,13 @@
+{
+  language: '中文',
+  langCode: 'zh_cn',   // if not specified will use folder
+  defaultExampleCaption: "点击在新标签页中打开",
+  title: 'three.js基础',
+  description: 'Three.js基础学习',
+  link: 'http://threejsfundamentals.org/',
+  commentSectionHeader: '<div>Questions? <a href="http://stackoverflow.com/questions/tagged/three.js">Ask on stackoverflow</a>.</div>\n        <div><a href="https://github.com/greggman/threejsfundamentals/issues/new?assignees=&labels=suggested+topic&template=suggest-topic.md&title=%5BSUGGESTION%5D">Suggestion</a>? <a href="https://github.com/greggman/threejsfundamentals/issues/new?assignees=&labels=&template=request.md&title=">Request</a>? <a href="https://github.com/greggman/threejsfundamentals/issues/new?assignees=&labels=bug+%2F+issue&template=bug-issue-report.md&title=">Issue</a>? <a href="https://github.com/greggman/threejsfundamentals/issues/new?assignees=&labels=bug+%2F+issue&template=bug-issue-report.md&title=">Bug</a>?</div>',
+  missing: "Sorry this article has not been translated yet. [Translations Welcome](https://github.com/greggman/threejsfundamentals)! 😄\n\n[Here's the original English article for now]({{{origLink}}}).",
+  toc: '内容列表',
+}
+
+

+ 293 - 0
threejs/lessons/zh_cn/threejs-fundamentals.md

@@ -0,0 +1,293 @@
+Title: Three.js基础
+Description: 学习Three.js的第一篇文章
+
+这是Three.js系列文章的第一篇。
+[Three.js](http://threejs.org)是一个尽可能简化在网页端获取3D
+内容的库。
+
+Three.js经常会和WebGL混淆,
+但也并不总是,three.js其实是使用WebGL来绘制三维效果的。
+[WebGL是一个只能画点、线和三角形的非常底层的系统](https://webglfundamentals.org). 
+想要用WebGL来做一些实用的东西通常需要大量的代码,
+这就是Three.js的用武之地。它帮我们处理了像场景、灯光、阴影、材质、贴图、空间运算、几乎所有你需要自己通过WebGL来实现的东西。
+
+这套教程假设你已经了解了JavaScript,因为大部分内容我们将会
+用到ES6的语法。[点击这里查看你需要提前掌握的东西](threejs-prerequisites.html)。 
+大部分支持Three.js的浏览器都会自动更新,所以部分用户应该都能运行本套教程的代码。
+如果你想在非常老的浏览器上运行此代码,
+你需要一个像[Babel](http://babel.io)一样的语法编译器 。
+当然使用非常老的浏览器的用户可能根本不能运行Three.js。
+
+人们在学习大多数编程语言的时候第一件事就是让电脑打印`"Hello World!"`。
+对于三维来说第一件事往往是创建一个三维的立方体。
+所以我们从"Hello Cube!"开始。
+
+首先我们需要一个canvas标签。
+
+```html
+<body>
+  <canvas id="c"></canvas>
+</body>
+```
+
+Three.js将会使用这个canvas标签所以我们要先获取它然后传给three.js。
+
+```html
+<script>
+'use strict';
+
+/* global THREE */
+
+function main() {
+  const canvas = document.querySelector('#c');
+  const renderer = new THREE.WebGLRenderer({canvas});
+  ...
+</script>
+```
+
+注意这里有一些细节。如果你没有给three.js传canvas,three.js会自己创建一个
+,但是你必须手动把它添加到文档中。在哪里添加可能会不一样这取决你怎么使用,
+我发现给three.js传一个canvas会更灵活一些。我可以将canvas放到任何地方,
+代码都会找到它,假如我有一段代码是将canvas插入到文档中,那么当需求变化时,
+我很可能必须去修改这段代码。
+
+在查找到canvas之后我们创建一个`WebGLRenderer`。渲染器负责拿到你提供的所有数据,
+然后将它渲染到canvas上。之前还有其他渲染器,比如`CSSRenderer`、`CanvasRenderer`。
+在将来可能还会有`WebGL2Renderer` 或者 `WebGPURenderer`。目前的话是 `WebGLRenderer`使用WebGL将三维渲染到canvas上。
+
+接下来我们需要一个摄像机。
+
+```js
+const fov = 75;
+const aspect = 2;  // the canvas default
+const near = 0.1;
+const far = 5;
+const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
+```
+
+`fov`是`field of view`的缩写。 当前的情况是垂直方向为75度。
+注意three.js中大多数的角用弧度表示,但是因为某些原因透视摄像机使用角度表示。
+
+`aspect`指canvas的显示比例。我们将在别的文章详细讨论,但是在默认情况下
+canvas是300x150像素,所以aspect为300/150或者说2.。
+
+`near`和`far`代表摄像机前方将要被渲染的空间。
+任何在这个范围前面或者后面的物体都将被裁剪(不绘制)。
+
+这四个参数定义了一个*"frustum"*。一个*frustum*是指一个像被削去顶部
+的金字塔形状。换句话说把*"frustum"*想象成其他形状比如球体、
+立方体、棱柱体、截椎体。 
+
+<img src="resources/frustum-3d.svg" width="500" class="threejs_center"/>
+
+近平面和远平面的高度由fov决定。
+两个平面的宽度由fov和aspect决定。
+
+截椎体内部的物体将被绘制,截椎体外的东西将不会被绘制。
+
+摄像机默认指向Z轴负方向,上方向朝向Y轴正方向。我们将会把立方体
+放置在坐标原点,所以我们需要往后移动摄像机才能看到物体。
+
+```js
+camera.position.z = 2;
+```
+
+下面是我们想要达到的效果。
+
+<img src="resources/scene-down.svg" width="500" class="threejs_center"/>
+
+上面的示意图中我们能看到摄像机的位置在`z = 2`。它朝向
+Z轴负方向。我们的截椎体从摄像机前方的0.1到5。因为这张图是俯视图,
+fov会受到aspect的影响。canvas的宽度是高度的两倍,
+所以水平视角会比我们设置的垂直视角75要大。
+
+然后我们创建一个`Scene`(场景)。`Scene`是three.js最基本的组成.
+需要three.js绘制的东西都需要加入到scene中。 我们将会
+在[scene是如何工作的](threejs-scenegraph.html)中详细讨论。
+
+```js
+const scene = new THREE.Scene();
+```
+
+然后我们创建一个包含盒子信息的`BoxGeometry`。
+几乎所有的希望在three.js中显示的物体都需要一个定义了组成三维物体的顶点的几何体。
+
+```js
+const boxWidth = 1;
+const boxHeight = 1;
+const boxDepth = 1;
+const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
+```
+
+然后我们创建一个基本的材质并设置它的颜色. Colors的值可以
+用css方式和十六进制来表示。
+
+```js
+const material = new THREE.MeshBasicMaterial({color: 0x44aa88});
+```
+
+然后创建一个`Mesh`. `Mesh`代表了`Geometry`(物体的形状)和`Material` (怎么
+绘制物体, 光滑还是平整, 什么颜色, 什么贴图等等)的组合,
+以及物体在场景中的位置、朝向、和缩放。
+
+```js
+const cube = new THREE.Mesh(geometry, material);
+```
+
+最后我们将mesh添加到场景中。
+
+```js
+scene.add(cube);
+```
+
+然后我们通过将scene和camera传递给renderer的render方法
+来渲染整个场景。
+
+```js
+renderer.render(scene, camera);
+```
+
+这里有一个实例。
+
+{{{example url="../threejs-fundamentals.html" }}}
+
+很难看出来这是一个三维的立方体,因为我们
+直视Z轴的负方向并且立方体和坐标轴是对齐的,
+所以我们只能看到一个面。
+
+我们来让立方体旋转起来,希望
+能看出是三维的。为了让它动起来我们需要在渲染循环函数中使用
+[`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame).
+
+这是我们的渲染循环函数。
+
+```js
+function render(time) {
+  time *= 0.001;  // convert time to seconds
+
+  cube.rotation.x = time;
+  cube.rotation.y = time;
+
+  renderer.render(scene, camera);
+
+  requestAnimationFrame(render);
+}
+requestAnimationFrame(render);
+```
+
+`requestAnimationFrame`会告诉浏览器你有那些东西想要做动画。
+传入一个函数作为回调函数。我们这里的函数是`render`。浏览器
+会调用你的函数然后如果你更新了跟页面显示有关的东西,
+浏览器就会重新渲染页面。我们这里是调用three.js的
+`renderer.render`函数来绘制我们的场景。
+
+`requestAnimationFrame` 会传入从页面加载到
+我们函数的时间. 传入的时间是毫秒数。我发现
+用秒会更简单所以我们把它转换成秒。
+
+然后我们把立方体的X轴和Y轴方向的旋转角度设置成当前时间。这些旋转角度
+是[弧度制](https://en.wikipedia.org/wiki/Radian)。一圈的弧度
+为2Π所以我们的立方体在每个方向旋转一周的时间为6.28
+秒。
+
+然后渲染我们的场景并且调用另一帧动画来继续我们的循环。
+
+在循环的未免我们调用一次`requestAnimationFrame`来开始循环渲染.
+
+{{{example url="../threejs-fundamentals-with-animation.html" }}}
+
+效果好了一些但还是很难看出是三维的。添加灯光会有帮助,
+所以我们来添加一盏灯光。three.js中有很多种类型的灯光,
+我们将在[后期文章](threejs-lights.html)中详细讨论。现在我们先创建一盏平行光。
+
+```js
+{
+  const color = 0xFFFFFF;
+  const intensity = 1;
+  const light = new THREE.DirectionalLight(color, intensity);
+  light.position.set(-1, 2, 4);
+  scene.add(light);
+}
+```
+
+平行光有一个位置和目标点。默认值都为 0, 0, 0。 我们这里
+设置灯光的位置为 -1, 2, 4 所以它位于摄像机前面的
+稍微左上方一点。目标点还是 0, 0, 0 所以它朝向
+坐标原点。
+
+我们还需要改变材质。`MeshBasicMaterial`材质不会受到灯光的
+影响。我们将他改成会受灯光影响的`MeshPhongMaterial`材质。
+
+```js
+-const material = new THREE.MeshBasicMaterial({color: 0x44aa88});  // greenish blue
++const material = new THREE.MeshPhongMaterial({color: 0x44aa88});  // greenish blue
+```
+
+下面开始生效了。
+
+{{{example url="../threejs-fundamentals-with-light.html" }}}
+
+现在应该可以很清楚的看出是三维的。
+
+为了更有乐趣我们再添加两个立方体。
+
+每个立方体将会使用同一个几何体但是不同的材质,
+这样每个立方体将会是不同的颜色。
+
+首先我们创建一个根据指定的颜色生成新材质的函数。
+然后函数会根据指定的几何体生成一个mesh,
+最后将他添加进场景并设置X轴的位置。
+
+```js
+function makeInstance(geometry, color, x) {
+  const material = new THREE.MeshPhongMaterial({color});
+
+  const cube = new THREE.Mesh(geometry, material);
+  scene.add(cube);
+
+  cube.position.x = x;
+
+  return cube;
+}
+```
+
+然后我们将使用三种不同的颜色和X轴位置调用三次函数,
+将生成的网格实例存在一个数组中。
+
+```js
+const cubes = [
+  makeInstance(geometry, 0x44aa88,  0),
+  makeInstance(geometry, 0x8844aa, -2),
+  makeInstance(geometry, 0xaa8844,  2),
+];
+```
+
+最后我们将在渲染函数中旋转三个立方体。我们
+给每个立方体设置了稍微不同的旋转角度。
+
+```js
+function render(time) {
+  time *= 0.001;  // convert time to seconds
+
+  cubes.forEach((cube, ndx) => {
+    const speed = 1 + ndx * .1;
+    const rot = time * speed;
+    cube.rotation.x = rot;
+    cube.rotation.y = rot;
+  });
+
+  ...
+```
+
+这里是结果.
+
+{{{example url="../threejs-fundamentals-3-cubes.html" }}}
+
+如果你对比上面的示意图可以看到
+效果符合我们的预想。位置为X = -2 和 X = +2
+的立方体有一部分在我们的截椎体外面。他们大部分是被
+包裹的,因为水平方向的视角非常大。
+
+希望这个简短的介绍能帮助你起步。 [Next up we'll cover
+making our code responsive so it is adaptable to multiple situations](threejs-responsive.html).
+

+ 344 - 0
threejs/lessons/zh_cn/threejs-prerequisites.md

@@ -0,0 +1,344 @@
+Title: Three.js先决条件
+Description: 使用此网站你需要了解的。
+
+这些文章意在帮助你学习如何使用three.js。
+假设你知道怎么使用JavaScript编程。假设
+你知道DOM是什么,怎么写HTML以及使用JavaScript创建
+DOM元素。假设你知道如何使用 `<script>`标签来
+引用外部的JavaScript文件以及行内脚本。
+假设你了解CSS并且知道
+[CSS选择器](https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors). 
+还假设你了解ES5、 ES6或者一些ES7。
+假设你知道浏览器通过事件和回调函数来运行JavaScript。
+假设你知道什么是闭包。
+
+这有一些简单的复习和笔记。
+
+## `document.querySelector` and `document.querySelectorAll`
+
+你可以使用`document.querySelector`来选择和CSS选择器
+匹配的第一个元素。 `document.querySelectorAll`返回
+所有和CSS选择器匹配的元素。
+
+## You don't need `onbody`
+
+很多20年前的页面像这样使用HTML
+
+    <body onload="somefunction()">
+
+这种风格已经被弃用了。将你的脚本放在
+页面的底部。
+
+```html
+<html>
+  <head>
+    ...
+  </head>
+  <body>
+     ...
+  </body>
+  <script src="script1.js"></script>
+  <script>
+    // inline javascript
+  </script>
+</html>
+```
+
+or [use the `defer` property](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script).
+
+## 不需要`type="text/javascript"`
+
+最新的
+
+    <script>...</script>
+
+过时的
+
+    <script type="text/javascript"></script>
+
+## 始终使用`strict`模式
+
+将`'use strict';`放在JavaScript文件的顶部。可以帮助减少很多bug。
+
+## 了解闭包如何工作
+
+```js
+function a(v) {
+  const foo = v;
+  return function() {
+     return foo;
+  };
+}
+
+const f = a(123);
+const g = a(456);
+console.log(f());  // prints 123
+console.log(g());  // prints 456
+```
+
+在上面的代码中函数`a`每次被调用都会创建一个新的函数。新函数
+会封存变量`foo`. 这里有 [更多信息](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures).
+
+## 理解`this`的工作原理
+
+`this`并不是什么魔法。它实际上像是一个像被自动传给函数的参数一样的变量。
+简单的说就是像这样直接调用函数
+
+    somefunction(a, b, c);
+
+`this`将会为`null` (使用严格模式时) 当你使用`.`操作符像这样调用函数时
+
+    someobject.somefunction(a, b, c);
+
+`this`将会被设置为`someobject`。
+
+令人困惑的部分是使用回调函数。
+
+     const callback = someobject.somefunction;
+     loader.load(callback);
+
+并没有像不熟悉的所期望的那样工作,因为当
+`loader.load`调用回调函数时并没有使用`.`操作符。
+所以默认`this`将会为null (除非loader明确将他设置为某些东西)。
+如果你希望`this`为`someobject`当回调函数执行时你需要
+通过将this绑定到函数来告诉JavaScript。
+
+     const callback = someobject.somefunction.bind(someobject);
+     loader.load(callback);
+
+[*this* article might help explain `this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this).
+
+## ES5/ES6/ES7 特性
+
+### `var`已经被弃用,使用`const`和`let`
+
+没有**任何**理由再使用`var`,基于此使用它被认为是
+坏习惯。大所数时间如果变量不会被重新分配使用`const`。
+变量会改变的情况下使用`let`。这将会帮助避免大量bug。
+
+### 使用`for(elem of collection)`而不是`for(elem in collection)`
+
+`for of`是新的,`for in`是旧的。 `for of`解决了`for in`的问题。
+
+举个例子,你可以像这样迭代一个对象的所以键/值对
+
+```js
+for (const [key, value] of Object.entries(someObject)) {
+  console.log(key, value);
+}
+```
+
+### 使用 `forEach`, `map`, 和 `filter`
+
+数组新增的函数[`forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach、
+[`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)和 
+[`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
+在现代JavaScript中使用都是相当广泛的。
+
+### 使用解构赋值
+
+假设有一个对象`const dims = {width: 300, height: 150}`
+
+老的代码
+
+     const width = dims.width;
+     const height = dims.height;
+
+新代码
+
+     const {width, height} = dims;
+
+### 使用对象声明简写
+
+老的代码
+
+```js
+ const width = 300;
+ const height = 150;
+ const obj = {
+   width: width,
+   height: height,
+   area: function() {
+     return this.width * this.height
+   },
+ };
+```
+
+新代码
+
+```js
+ const width = 300;
+ const height = 150;
+ const obj = {
+   width,
+   height,
+   area() {
+     return this.width * this.height;
+   },
+ };
+```
+
+### 使用扩展运算符`...`
+
+扩展运算符有大量的用途。例如
+
+```js
+ function log(className, ...args) {
+   const elem = document.createElement('div');
+   elem.className = className;
+   elem.textContent = [...args].join(' ');
+   document.body.appendChild(elem);
+ }
+```
+
+另一个例子
+
+```js
+const position = [1, 2, 3];
+somemesh.position.set(...position);
+```
+
+### 使用`class`
+
+大多数人都不熟悉在ES5之前生成类对象的语法。
+ES5之后你现在可以[使用`class`
+关键字](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
+接近于C++/C#/Java的语法。
+
+### 理解 getters 和 setters
+
+[Getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)和
+[setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set)是
+在大多数现代语言中常见的。ES6`class`语法
+让他们比ES6之前的更容易。
+
+### 合理使用箭头函数
+
+回调函数和promise使用箭头函数非常有用
+
+```js
+loader.load((texture) => {
+  // use textrue
+});
+```
+
+箭头函数会绑定`this`,它是下面的简写
+
+```js
+(function(args) {/* code */}).bind(this))
+```
+
+### Promises 以及 async/await
+
+Promises改善异步代码的处理。Async/await改善
+promise的使用。
+
+这是一个需要深入了解的话题你可以[在这里
+细读promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises)
+和[async/await](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await).
+
+### 使用模板字符串
+
+模板字符串是使用反引号代替引号的字符串。
+
+    const foo = `this is a template literal`;
+
+模板字符串有两个基本的特点。一个是它可以多行
+
+```js
+const foo = `this
+is
+a
+template
+literal`;
+const bar = "this\nis\na\ntemplate\nliteral";
+```
+
+上面的`foo`和`bar`是一样的。
+
+另一个是你可以超越字符串模式
+使用`${javascript表达式}`插入JavaScript代码段。这是模板部分。比如:
+
+```js
+const r = 192;
+const g = 255;
+const b = 64;
+const rgbCSSColor = `rgb(${r},${g},${b})`;
+```
+
+or
+
+```js
+const color = [192, 255, 64];
+const rgbCSSColor = `rgb(${color.join(',')})`;
+```
+
+or
+
+```js
+const aWidth = 10;
+const bWidth = 20;
+someElement.style.width = `${aWidth + bWidth}px`;
+```
+
+# 学习JavaScript代码风格。
+
+尽管欢迎您以任何方式组织您的代码,但至少有一个约定您应该知道。
+在JavaScript中变量、函数名、方法名
+都是小驼峰。构造函数、类名都是
+大驼峰。如果你遵守这些约定你的diamagnetic将会和大部分JavaScript匹配。
+
+# 考虑使用Visual Studio Code
+
+当然你想想用什么编辑器就用什么但是如果你没尝试过它那就考虑下
+使用[Visual Studio Code](https://code.visualstudio.com/)来写JavaScript。
+安装完之后[设置
+eslint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)。
+可能会花几分钟来设置但是会对你寻找JavaScript的bug有极大的帮助。
+
+一些例子
+
+如果你开启[`no-undef`规则](https://eslint.org/docs/rules/no-undef)然后
+VSCode通过ESLint将会警告你很多没有定义的变量。 
+
+<div class="threejs_center"><img style="width: 615px;" src="resources/images/vscode-eslint-not-defined.png"></div>
+
+上面你可以看到我将`doTheThing`误写成了`doThing`。有一个红色的曲线
+在`doThing`下面并且鼠标悬停会提醒我们它未定义。这样就避免了一个错误。
+
+使用`THREE`会得到警告所以将`/* global THREE */`放在你的
+JavaScript文件的顶部来告诉eslint`THREE`的存在。
+
+<div class="threejs_center"><img style="width: 615px;" src="resources/images/vscode-eslint-not-a-constructor.png"></div>
+
+上面你可以看到eslint知道使用`UpperCaseNames`规则的是构造函数
+所以你应该使用`new`操作符。另一个错误被捕捉并避免了。这是[the
+`new-cap`规则](https://eslint.org/docs/rules/new-cap)。
+
+这里有[100多条规则你可以打开或者关闭或者自定义
+](https://eslint.org/docs/rules/)。比如上面我提醒你
+应该使用`const`和`let`代替`var`。
+
+这里我使用了`var`它警告我应该使用`let`或者`const`
+
+<div class="threejs_center"><img style="width: 615px;" src="resources/images/vscode-eslint-var.png"></div>
+
+这里我是用了`let`但是它发现我一直没改变值所以建议我使`const`。
+
+<div class="threejs_center"><img style="width: 615px;" src="resources/images/vscode-eslint-let.png"></div>
+
+当然如果你更希望继续使用`var`你只要关闭那条规则。
+如我上面所说所以我更喜欢使用`const`和`let`而不是`var`因为
+他们工作的更好而且能减少bugs。
+
+对于确实需要重写这些规则的情况[你可以添加注释
+来禁用
+他们](https://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments)
+通过单行或者一段代码。
+
+# 如果你确实需要支持老的浏览器请使用编译器
+
+大多数现代浏览器都是自动更新的,所以使用这些新的特性会帮助你提高效率 
+和避免bug。意思是说,如果你正在做一个需要支持老的浏览器的项目,
+[有工具会把ES5/ES6/ES7代码
+转换成ES5之前的Javascript](https://babeljs.io).

+ 235 - 0
threejs/lessons/zh_cn/threejs-responsive.md

@@ -0,0 +1,235 @@
+Title: Three.js响应式设计
+Description: 如何让你的three.js适应不同尺寸的显示器。
+
+这是three.js系列文章的第二篇。
+第一篇是[关于基础](threejs-fundamentals.html).
+如果你还没有阅读第一篇那你应该从第一篇开始。
+
+这篇文章是关于如何让你的three.js应用能适应任何情况。
+让一个网页是响应式的通常是指让网页能在从桌面到平板再到手机
+不同尺寸的显示器上显示良好。
+
+对three.js来说有更多的情况要考虑。例如,在左侧、右侧、顶部或底部
+具有控件的三维编辑器是我们可能需要处理的。文档中部的在线例子
+是我们要处理的另一个例子。
+
+上一个例子中我们使用了一个没有设置css和尺寸的canvas。
+
+```html
+<canvas id="c"></canvas>
+```
+
+那个canvas默认300x150像素。
+
+在web平台推荐使用css来设置物体的尺寸。
+
+我们通过添加CSS来让canvas填充整个页面。
+
+```html
+<style>
+html, body {
+   margin: 0;
+   height: 100%;
+}
+#c {
+   width: 100%;
+   height: 100%;
+   display: block;
+}
+</style>
+```
+
+HTML中的body默认有5个像素的margin值所以设置margin为0来移除margin值。
+设置html和body的高度为100%让他们充满整个窗口。不然的话他们的大小只会
+和填充他们的内容一样。
+
+然后我们让`id=c`的元素的尺寸是容器的100%这里是body标签。  
+
+最后我们设置它的`display`为`block`。canvas的display默认为
+`inline`。行内元素的末尾会有空格。
+通过设置canvas为块级元素就能消除这个空格。
+
+这里是结果。
+
+{{{example url="../threejs-responsive-no-resize.html" }}}
+
+你可以看到canvas充满了整个页面但是有两个问题。
+第一是我们的立方体被拉伸了。他们不是立方体了更像是个盒子
+太高或者太宽。 在新标签中打开它然后改变尺寸你就能看到立方体
+是怎么在宽高上被拉伸的。
+
+<img src="resources/images/resize-incorrect-aspect.png" width="407" class="threejs_center">
+
+另一个问题是立方体看起来分辨率太低或者说块状化或者有点模糊。
+将窗口拉伸的非常大你就能看到问题。
+
+<img src="resources/images/resize-low-res.png" class="threejs_center">
+
+我们先解决拉伸的问题。为此我们要将相机的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">
+
+我们现在来解决块状化的问题。
+
+canvas元素有两个尺寸。一个是canvas在页面上的显示尺寸,
+是我们用CSS来设置的。另一个尺寸是
+canvas本身像素的数量。这和图片一样。
+比如我们有一个128x64像素的图片然后我们可以通过CSS让它显示为
+400x200像素。
+
+```html
+<img src="some128x64image.jpg" style="width:400px; height:200px">
+```
+
+一个canvas的内部尺寸,它的分辨率,通常被叫做drawingbuffer尺寸。
+在three.js中我们可以通过调用`renderer.setSize`来设置canvas的drawingbuffer。
+我们应该选择什么尺寸? 最显而易见的是"和canvas的显示尺寸一样"。
+再一次,我们可以使用canvas的`clientWidth`和`clientHeight`属性。
+
+我们写一个函数来检查渲染器的canvas尺寸是不是和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规范的一个有趣部分,如果它已经是我们想要的大小,最好不要设置相同的大小.
+ 
+一旦我们知道了是否需要调整大小我们就调用`renderer.setSize`然后
+传入新的宽高。在末尾传入`false`很重要。
+`render.setSize`默认会设置canvas的CSS尺寸但这并不是我们想要的。
+我们希望浏览器能继续工作就像其他使用CSS来定义尺寸的其他元素。我们不希望
+three.js使用canvas和其他元素不一样。
+
+注意如果我们的canvas大小被调整了那函数会返回true。我们可以利用
+这个来检查是否有其他的东西应该更新。我们修改渲染循环
+来使用我们的新函数。
+
+```js
+function render(time) {
+  time *= 0.001;
+
++  if (resizeRendererToDisplaySize(renderer)) {
++    const canvas = renderer.domElement;
++    camera.aspect = canvas.clientWidth / canvas.clientHeight;
++    camera.updateProjectionMatrix();
++  }
+
+  ...
+```
+
+因为只有canvas的显示尺寸变化时aspect值才变化所以我们
+只在`resizeRendererToDisplaySize`函数返回`true`时才设置摄像机的aspect。
+
+{{{example url="../threejs-responsive.html" }}}
+
+现在渲染的分辨率应该是和canvas的显示尺寸一样的。
+
+为了说清楚让CSS处理调整尺寸我们将代码
+放进[separate `.js` file](../threejs-responsive.js)。
+这里还有一些例子我们让CSS决定尺寸的大小并且注意我们并没有改变任何
+代码来让他们工作。
+
+我们将立方体放在文字段落的中间。
+
+{{{example url="../threejs-responsive-paragraph.html" startPane="html" }}}
+
+这是我们在编辑器样式布局中使用的相同代码,右侧的控制区域可以调整大小。
+
+{{{example url="../threejs-responsive-editor.html" startPane="html" }}}
+
+重点注意我们的代码并没有改变,只有我们的HTML和CSS变了。
+
+## 应对HD-DPI显示器
+
+HD-DPI代表每英寸高密度点显示器(视网膜显示器)。它指的是当今大多数的Mac和windows机器以及几乎所有的智能手机。
+
+浏览器中的工作方式是不管屏幕的分辨率有多高使用CSS像素设置尺寸会被认为是一样的。
+同样的物理尺寸浏览器会渲染出字体的更多细节。
+
+使用three.js有多种方法来应对HD-DPI。
+
+第一种就是不做任何特别的事情。这可以说是最常见的。
+渲染三维图形需要大量的GPU处理能力。移动端的GPU能力比桌面端的要弱。至少截止到2018年,
+手机都有非常高的分辨率显示器。
+目前最好的手机的HD-DPI比例为3x,意思是非高密度点显示器上的一个像素在高密度显示器上是9个像素。 
+意味着需要9倍的渲染。
+
+计算9倍的像素是个大工程所以如果保持代码不变我们将计算一个像素然后浏览器将以三倍大小绘制(3x3=9像素)。
+
+对于大型的three.js应用来说上面就是你想要的否侧你的帧速率会很低。
+
+尽管如此如果你确实想用设备的分辨率来渲染,three.js中有两种方法来实现。
+
+一种是使用renderer.setPixelRatio来告诉three.js分辨率的倍数。
+访问浏览器从CSS像素到设备像素的倍数然后传给three.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;
+      const height = canvas.clientHeight * pixelRatio;
+      const needResize = canvas.width !== width || canvas.height !== height;
+      if (needResize) {
+        renderer.setSize(width, height, false);
+      }
+      return needResize;
+    }
+```
+
+第二章方法从客观上来说更好。为什么?因为我拿到了我想要的。
+在使用three.js时有很多种情况下我们需要知道canvas的drawingBuffer的确切尺寸。
+比如制作后期处理滤镜或者我们在操作着色器需要访问gl_FragCoord变量,如果我们截屏或者给GPU
+读取像素,绘制到二维的canvas等等。
+通过我们自己处理我们会一直知道使用的尺寸是不是我们需要的。
+幕后并没有什么特殊的魔法发生。
+
+这是一个使用上面代码的例子。
+
+{{{example url="../threejs-responsive-hd-dpi.html" }}}
+
+可能很难看出区别但是如果你有一个HD-DPI显示器
+和上面的例子做对比你就能发现边角更清晰。
+
+这篇文章涵盖了一个非常基础但是很有必要的主题。接下来我们快速
+[过一遍three.js提供的基本的东西 ](threejs-primitives.html).
+

+ 56 - 0
threejs/lessons/zh_cn/threejs-setup.md

@@ -0,0 +1,56 @@
+Title: Three.js设置
+Description: 如何为你的three.js设置开发环境
+
+这是three.js系列文章的其中之一。
+第一篇是[关于three.js基础](threejs-fundamentals.html)。
+如果你还没有阅读那你应该从那开始。
+
+在我们深入之前我们需要讨论一下设置你的电脑来开发。
+尤其是,因为安全的原因,
+WebGL不能直接从你的硬件使用图片。意思是说
+为了能开发你需要使用web服务。幸运的是
+web服务很容易设置和使用。
+
+首先如果你喜欢你可以从[这个链接](https://github.com/greggman/threejsfundamentals/archive/gh-pages.zip)
+下载整个网站。
+一旦下载完成双击文件来解压。
+
+下一步下载一个简单的web服务。
+
+如果你更喜欢有用户界面的web服务,这有一个
+[Servez](https://greggman.github.io/servez)
+
+{{{image url="resources/servez.gif" className="border" }}}
+
+只要将他指向你解压的文件夹,点击"Start",然后
+打开你的浏览器的[`http://localhost:8080/`](http://localhost:8080/)或者
+你想浏览例子打开[`http://localhost:8080/threejs`](http://localhost:8080/threejs)。
+
+点击stop或者推出Servez来停止服务。
+如果你更喜欢命令行(我就是),另一种方法是使用[node.js](https://nodejs.org)。
+下载,安装,然后打开一个command prompt / console / terminal窗口。 如果你是在Windows上安装程序会添加一个特别的"Node Command Prompt"所以使用它。
+
+然后安装[`http-server`](https://github.com/indexzero/http-server)通过输入
+
+    npm -g install http-server
+
+如果你是OSX使用
+
+    sudo npm -g install http-server
+
+一旦你输入完成
+
+    http-server path/to/folder/where/you/unzipped/files
+
+它会打印像这样的东西
+
+{{{image url="resources/http-server-response.png" }}}
+
+然后在你的浏览器中打开[`http://localhost:8080/`](http://localhost:8080/)。
+
+如果你没有指定路径那么http-server会使用当前的文件夹。
+
+如果这些都不是你的选择
+[这里有很多其他的服务可供选择](https://stackoverflow.com/questions/12905426/what-is-a-faster-alternative-to-pythons-http-server-or-simplehttpserver)。
+
+现在你有了服务我们可以移步到[纹理](threejs-textures.html).

+ 66 - 0
threejs/lessons/zh_cn/toc.html

@@ -0,0 +1,66 @@
+<ul>
+  <li>Basics</li>
+  <ul>
+    <li><a href="/threejs/lessons/threejs-fundamentals.html">Fundamentals</a></li>
+    <li><a href="/threejs/lessons/threejs-responsive.html">Responsive Design</a></li>
+    <li><a href="/threejs/lessons/threejs-prerequisites.html">Prerequisites</a></li>
+    <li><a href="/threejs/lessons/threejs-setup.html">Setup</a></li>
+  </ul>
+  <li>Solutions</li>
+  <ul>
+    <li><a href="/threejs/lessons/threejs-load-obj.html">Load an .OBJ file</a></li>
+    <li><a href="/threejs/lessons/threejs-load-gltf.html">Load a .GLTF file</a></li>
+    <li><a href="/threejs/lessons/threejs-backgrounds.html">Add a Background or Skybox</a></li>
+    <li><a href="/threejs/lessons/threejs-transparency.html">How to Draw Transparent Objects</a></li>
+    <li><a href="/threejs/lessons/threejs-multiple-scenes.html">Multiple Canvases, Multiple Scenes</a></li>
+    <li><a href="/threejs/lessons/threejs-picking.html">Picking Objects with the mouse</a></li>
+    <li><a href="/threejs/lessons/threejs-post-processing.html">Post Processing</a></li>
+    <li><a href="/threejs/lessons/threejs-post-processing-3dlut.html">Applying a LUT File for effects</a></li>
+    <li><a href="/threejs/lessons/threejs-shadertoy.html">Using Shadertoy shaders</a></li>
+    <li><a href="/threejs/lessons/threejs-align-html-elements-to-3d.html">Aligning HTML Elements to 3D</a></li>
+    <li><a href="/threejs/lessons/threejs-indexed-textures.html">Using Indexed Textures for Picking and Color</a></li>
+    <li><a href="/threejs/lessons/threejs-canvas-textures.html">Using A Canvas for Dynamic Textures</a></li>
+    <li><a href="/threejs/lessons/threejs-billboards.html">Billboards and Facades</a></li>
+  </ul>
+  <li>WebVR</li>
+  <ul>
+    <li><a href="/threejs/lessons/threejs-webvr.html">WebVR - Basics</a></li>
+    <li><a href="/threejs/lessons/threejs-webvr-look-to-select.html">WebVR - Look To Select</a></li>
+    <li><a href="/threejs/lessons/threejs-webvr-point-to-select.html">WebVR - Point To Select</a></li>
+  </ul>
+  <li>Optimization</li>
+  <ul>
+    <li><a href="/threejs/lessons/threejs-optimize-lots-of-objects.html">Optimizing Lots of Objects</a></li>
+    <li><a href="/threejs/lessons/threejs-optimize-lots-of-objects-animated.html">Optimizing Lots of Objects Animated</a></li>
+    <li><a href="/threejs/lessons/threejs-offscreencanvas.html">Using OffscreenCanvas in a Web Worker</a></li>
+  </ul>
+  <li>Tips</li>
+  <ul>
+    <li><a href="/threejs/lessons/threejs-rendering-on-demand.html">Rendering On Demand</a></li>
+    <li><a href="/threejs/lessons/threejs-debugging-javascript.html">Debugging JavaScript</a></li>
+    <li><a href="/threejs/lessons/threejs-debugging-glsl.html">Debugging GLSL</a></li>
+  </ul>
+  <li>Fundamentals</li>
+  <ul>
+    <li><a href="/threejs/lessons/threejs-primitives.html">Primitives</a></li>
+    <li><a href="/threejs/lessons/threejs-scenegraph.html">Scenegraph</a></li>
+    <li><a href="/threejs/lessons/threejs-materials.html">Materials</a></li>
+    <li><a href="/threejs/lessons/threejs-textures.html">Textures</a></li>
+    <li><a href="/threejs/lessons/threejs-lights.html">Lights</a></li>
+    <li><a href="/threejs/lessons/threejs-cameras.html">Cameras</a></li>
+    <li><a href="/threejs/lessons/threejs-shadows.html">Shadows</a></li>
+    <li><a href="/threejs/lessons/threejs-fog.html">Fog</a></li>
+    <li><a href="/threejs/lessons/threejs-rendertargets.html">Render Targets</a></li>
+    <li><a href="/threejs/lessons/threejs-custom-geometry.html">Custom Geometry</a></li>
+    <li><a href="/threejs/lessons/threejs-custom-buffergeometry.html">Custom BufferGeometry</a></li>
+  </ul>
+  <li>Reference</li>
+  <ul>
+    <li><a href="/threejs/lessons/threejs-material-table.html">Material Table</a></li>
+  </ul>
+</ul>
+<ul>
+  <li><a href="https://github.com/greggman/threejsfundamentals">github</a></li>
+  <li><a href="https://threejs.org">three.js</a></li>
+  <li><a href="https://threejs.org/docs/">three.js docs</a></li>
+</ul>