Browse Source

update the chinese threejsfundamentals article

xiaodong 4 years ago
parent
commit
b7e0b6de0f
1 changed files with 114 additions and 27 deletions
  1. 114 27
      threejs/lessons/zh_cn/threejs-fundamentals.md

+ 114 - 27
threejs/lessons/zh_cn/threejs-fundamentals.md

@@ -31,21 +31,35 @@ Three.js经常会和WebGL混淆,
 
 
 * 有一个`Renderer`。这可以说是three.js的主要对象。你传入了一个`Scene`和一个`Camera`到`Renderer`里面,然后他来渲染 (画)出在相机视椎体中的3D场景,作为一个2D的图片在画布上。
 * 有一个`Renderer`。这可以说是three.js的主要对象。你传入了一个`Scene`和一个`Camera`到`Renderer`里面,然后他来渲染 (画)出在相机视椎体中的3D场景,作为一个2D的图片在画布上。
 
 
-* 有一个[scenegraph](threejs-scenegraph.html) 它是一个类似结构的树,由很多对象组成,比如一个`Scene`对象 ,多个`Mesh`对象,`Light`对象,`Group`,`Object3D`,和`Camera`对象。一个`Scene`对象定义了场景图的根,并包含背景色和雾等属性。这些对象定义了一个分层的父/子树的结构,并且展现出对象出现的地方和他们的方向。子对象的位置和方向是相对于父对象而言的。比如说汽车的轮子是汽车的子对象,这样移动和定位汽车就会自动移动轮子。你可以了解更多在 [the article on scenegraphs](threejs-scenegraph.html) 中。
+* 有一个[场景图](threejs-scenegraph.html) 它是一个类似结构的树,由很多对象组成,比如一个`Scene`对象 ,多个`Mesh`对象,`Light`对象,`Group`,`Object3D`,和`Camera`对象。一个`Scene`对象定义了场景图最基本的要素,并包含背景色和雾等属性。这些对象定义了一个分层的父/子树的结构,并且展现出对象出现的地方和他们的方向。子对象的位置和方向是相对于父对象而言的。比如说汽车的轮子是汽车的子对象,这样移动和定位汽车就会自动移动轮子。你可以了解更多在[场景图的文章](threejs-scenegraph.html)中。
 
 
-  注意图中`Camera`是一半在场景图中,一半在场景图外的。这表示在three.js中,不像其他的对象一样,一个`Camera`不一定要在场景图中起作用。就像其他的对象一样,一个`Camera`,作为一些其他对象的子对象,将会相对他的父对象移动和朝向。这有一个例子,放置多个`Camera`对象在一个场景图中在 [the article on scenegraphs](threejs-scenegraph.html) 的结尾部分。
+  注意图中`Camera`是一半在场景图中,一半在场景图外的。这表示在three.js中,不像其他的对象一样,一个`Camera`不一定要在场景图中起作用。就像其他的对象一样,一个`Camera`,作为一些其他对象的子对象,将会跟随他的父对象移动和朝向。这有一个例子,放置多个`Camera`对象在一个场景图中在[场景图的文章](threejs-scenegraph.html)的结尾部分。
 
 
 * `Mesh`对象代表用一个特定的`Material`绘制一个特定的`Geometry`。`Material`对象和`Geometry`对象可以被多个`Mesh`对象使用。比如在不同的位置画两个蓝色立方体,我们会需要两个`Mesh`对象来代表每一个立方体的位置和方向。我们只需要一个`Geometry`来存放立方体的顶点数据,和一个`Material`来定义蓝色就可以了。两个`Mesh`对象都涉及到相同的`Geometry`对象和`Material`对象。
 * `Mesh`对象代表用一个特定的`Material`绘制一个特定的`Geometry`。`Material`对象和`Geometry`对象可以被多个`Mesh`对象使用。比如在不同的位置画两个蓝色立方体,我们会需要两个`Mesh`对象来代表每一个立方体的位置和方向。我们只需要一个`Geometry`来存放立方体的顶点数据,和一个`Material`来定义蓝色就可以了。两个`Mesh`对象都涉及到相同的`Geometry`对象和`Material`对象。
 
 
-* `Geometry`对象代表一些几何体,比如说球体、立方体、平面、狗、猫、人、树、建筑等的顶点信息。Three.js提供了多种内置的 [基本元素](threejs-primitives.html) 。你也可以 [create custom geometry](threejs-custom-geometry.html) 并且 [load geometry from files](threejs-load-obj.html)。
+* `Geometry`对象代表一些几何体,比如说球体、立方体、平面、狗、猫、人、树、建筑等的顶点信息。Three.js提供了多种内置的[基本元素](threejs-primitives.html) 。你也可以[创建自定义几何体](threejs-custom-geometry.html)并且[从文件中加载几何体](threejs-load-obj.html)。
 
 
-* `Material` objects represent
-  [the surface properties used to draw geometry](threejs-materials.html)
-  including things like the color to use and how shiny it is. A `Material` can also
-  reference one or more `Texture` objects which can be used, for example, 
-  to wrap an image onto the surface of a geometry.
+* `Material`对象代表[绘制几何体的表面属性](threejs-materials.html),包括使用的颜色,和光亮程度。一个`Material`可以引用一个或多个`Texture`对象,这些对象可以用来,例如,将图像包裹到几何体的表面。
 
 
-首先我们需要一个canvas标签。
+* `Texture`对象通常代表图片要么[从图像文件中加载](threejs-textures.html),[在画布上形成](threejs-canvas-textures.html),要么 [由另一个场景渲染出](threejs-rendertargets.html)。
+
+* `Light`对象代表[不同种类的光](threejs-lights.html)。
+
+考虑以上所有注意事项,我们接下来要做一个最小的*"Hello Cube"* 设置,像下面这样
+
+<div class="threejs_center"><img src="resources/images/threejs-1cube-no-light-scene.svg" style="width: 500px;"></div>
+
+首先让我们先来加载three.js
+
+```html
+<script type="module">
+import * as THREE from './resources/threejs/r119/build/three.module.js';
+</script>
+```
+
+把`type="module"`放到script标签中很重要。这可以让我们使用`import`关键字加载three.js。还有其他的方法可以加载three.js,但是r106开始,推荐使用模块的方式。模块的优点是可以很方便地导入需要的其他模块。这样我们就不用再手动加载它们所依赖的额外脚本了。
+
+下一步我们需要一个`<canvas>`标签。
 
 
 ```html
 ```html
 <body>
 <body>
@@ -59,10 +73,10 @@ Three.js将会使用这个canvas标签所以我们要先获取它然后传给thr
 <script type="module">
 <script type="module">
 import * as THREE from './resources/threejs/r119/build/three.module.js';
 import * as THREE from './resources/threejs/r119/build/three.module.js';
 
 
-function main() {
-  const canvas = document.querySelector('#c');
-  const renderer = new THREE.WebGLRenderer({canvas});
-  ...
++function main() {
++  const canvas = document.querySelector('#c');
++  const renderer = new THREE.WebGLRenderer({canvas});
++  ...
 </script>
 </script>
 ```
 ```
 
 
@@ -95,9 +109,8 @@ canvas是300x150像素,所以aspect为300/150或者说2.。
 `near`和`far`代表摄像机前方将要被渲染的空间。
 `near`和`far`代表摄像机前方将要被渲染的空间。
 任何在这个范围前面或者后面的物体都将被裁剪(不绘制)。
 任何在这个范围前面或者后面的物体都将被裁剪(不绘制)。
 
 
-这四个参数定义了一个*"frustum"*。一个*frustum*是指一个像被削去顶部
-的金字塔形状。换句话说把*"frustum"*想象成其他形状比如球体、
-立方体、棱柱体、截椎体。 
+这四个参数定义了一个 *"frustum"*(译者注:视椎体)。 *frustum*是指一个像被削去顶部
+的金字塔形状。换句话说,可以把"frustum"想象成其他形状比如球体、立方体、棱柱体、截椎体。 
 
 
 <img src="resources/frustum-3d.svg" width="500" class="threejs_center"/>
 <img src="resources/frustum-3d.svg" width="500" class="threejs_center"/>
 
 
@@ -117,10 +130,7 @@ camera.position.z = 2;
 
 
 <img src="resources/scene-down.svg" width="500" class="threejs_center"/>
 <img src="resources/scene-down.svg" width="500" class="threejs_center"/>
 
 
-上面的示意图中我们能看到摄像机的位置在`z = 2`。它朝向
-Z轴负方向。我们的截椎体从摄像机前方的0.1到5。因为这张图是俯视图,
-fov会受到aspect的影响。canvas的宽度是高度的两倍,
-所以水平视角会比我们设置的垂直视角75要大。
+上面的示意图中我们能看到摄像机的位置在`z = 2`。它朝向Z轴负方向。我们的截椎体从摄像机前方的0.1到5。因为这张图是俯视图,fov会受到aspect的影响。canvas的宽度是高度的两倍,所以水平视角会比我们设置的垂直视角75度要大。
 
 
 然后我们创建一个`Scene`(场景)。`Scene`是three.js最基本的组成.
 然后我们创建一个`Scene`(场景)。`Scene`是three.js最基本的组成.
 需要three.js绘制的东西都需要加入到scene中。 我们将会
 需要three.js绘制的东西都需要加入到scene中。 我们将会
@@ -147,9 +157,11 @@ const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
 const material = new THREE.MeshBasicMaterial({color: 0x44aa88});
 const material = new THREE.MeshBasicMaterial({color: 0x44aa88});
 ```
 ```
 
 
-然后创建一个`Mesh`. `Mesh`代表了`Geometry`(物体的形状)和`Material` (怎么
-绘制物体, 光滑还是平整, 什么颜色, 什么贴图等等)的组合,
-以及物体在场景中的位置、朝向、和缩放。
+然后创建一个`Mesh`。一个`Mesh`代表了三件事情的合集
+
+1. `Geometry`(物体的形状)
+2. `Material` (怎么绘制物体, 光滑还是平整, 什么颜色, 什么贴图等等)的组合
+3. 对象在场景中相对于他父对象的位置、朝向、和缩放。下面的代码父对象是场景。
 
 
 ```js
 ```js
 const cube = new THREE.Mesh(geometry, material);
 const cube = new THREE.Mesh(geometry, material);
@@ -161,8 +173,7 @@ const cube = new THREE.Mesh(geometry, material);
 scene.add(cube);
 scene.add(cube);
 ```
 ```
 
 
-然后我们通过将scene和camera传递给renderer的render方法
-来渲染整个场景。
+然后我们通过scene和camera传递给renderer的render方法来渲染整个场景。
 
 
 ```js
 ```js
 renderer.render(scene, camera);
 renderer.render(scene, camera);
@@ -244,6 +255,10 @@ requestAnimationFrame(render);
 +const material = new THREE.MeshPhongMaterial({color: 0x44aa88});  // greenish blue
 +const material = new THREE.MeshPhongMaterial({color: 0x44aa88});  // greenish blue
 ```
 ```
 
 
+这是我们新的项目结构
+
+<div class="threejs_center"><img src="resources/images/threejs-1cube-with-directionallight.svg" style="width: 500px;"></div>
+
 下面开始生效了。
 下面开始生效了。
 
 
 {{{example url="../threejs-fundamentals-with-light.html" }}}
 {{{example url="../threejs-fundamentals-with-light.html" }}}
@@ -309,6 +324,78 @@ function render(time) {
 的立方体有一部分在我们的截椎体外面。他们大部分是被
 的立方体有一部分在我们的截椎体外面。他们大部分是被
 包裹的,因为水平方向的视角非常大。
 包裹的,因为水平方向的视角非常大。
 
 
-希望这个简短的介绍能帮助你起步。 [Next up we'll cover
-making our code responsive so it is adaptable to multiple situations](threejs-responsive.html).
+我们的项目现在有了这样的结构
+
+<div class="threejs_center"><img src="resources/images/threejs-3cubes-scene.svg" style="width: 610px;"></div>
+
+正如你看见的那样,我们有三个`Mesh`引用了相同的`BoxGeometry`。每个`Mesh`引用了一个单独的
+`MeshPhongMaterial`来显示不同的颜色。
+
+希望这个简短的介绍能帮助你起步。[接下来我们将介绍如何使我们的代码具有响应性,从而使其能够适应多种情况](threejs-responsive.html).
+
+<div id="es6" class="threejs_bottombar">
+<h3>es6模块,three.js,和文件夹结构</h3>
+<p>从r106版本开始,使用three.js的首选方式是通过<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">es6模块</a>。</p>
+<p>
+在一个脚本中,es6模块可以通过<code>import</code>关键字加载或者通过<code>&lt;script type="module"&gt;</code>行内标签。这有一个两种方法都用的例子。
+</p>
+<pre class=prettyprint>
+&lt;script type="module"&gt;
+import * as THREE from './resources/threejs/r119/build/three.module.js';
 
 
+...
+
+&lt;/script&gt;
+</pre>
+<p>
+路径必须是绝对或相对的。相对路径通常由<code>./</code>或者<code>../</code>开头,和其他标签不同如<code>&lt;img&gt;</code>和<code>&lt;a&gt;</code>.
+</p>
+<p>
+只要它们的绝对路径完全相同,对同一脚本的引用将只被加载一次。对于three.js这意味着它需要你把所有的实例的库放在正确的文件夹结构中。
+</p>
+<pre class="dos">
+someFolder
+ |
+ ├-build
+ | |
+ | +-three.module.js
+ |
+ +-examples
+   |
+   +-jsm
+     |
+     +-controls
+     | |
+     | +-OrbitControls.js
+     | +-TrackballControls.js
+     | +-...
+     |
+     +-loaders
+     | |
+     | +-GLTFLoader.js
+     | +-...
+     |
+     ...
+</pre>
+<p>
+之所以需要这种文件夹结构,是因为像<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>
+使用相同的结构保证了当你导入three和任一示例库时,它们都会引用同一个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>在使用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>如果你偏向于旧式的<code>&lt;script src="path/to/three.js"&gt;&lt;/script&gt;</code>样式,你可以查看<a href="https://r105.threejsfundamentals.org">这个网站的旧版本</a>。
+Three.js的政策是不担心向后的兼容性。他们希望你使用特定的版本,就像希望你下载代码并把它放在你的项目中一样。当升级到较新的版本时,你可以阅读 <a href="https://github.com/mrdoob/three.js/wiki/Migration-Guide">迁移指南</a> 看看你需要改变什么。如果要同时维护一个es6模块和一个类脚本版本的网站,那工作量就太大了,所以今后本网站将只显示es6模块样式。正如其他地方说过的那样,为了支持旧版浏览器,请考虑使用<a href="https://babeljs.io">转换器</a>。</p>
+</div>