Browse Source

before translation

yui 4 years ago
parent
commit
43847ac1cf
1 changed files with 115 additions and 41 deletions
  1. 115 41
      threejs/lessons/ja/threejs-custom-buffergeometry.md

+ 115 - 41
threejs/lessons/ja/threejs-custom-buffergeometry.md

@@ -1,28 +1,63 @@
-Title: Three.jsのカスタムバッファジオメトリ
-Description: カスタムバッファジオメトリを作る
-TOC: カスタムバッファジオメトリ
-
-[前回の記事](threejs-custom-geometry.html)では`Geometry`を紹介しました。この記事では`BufferGeometry`を紹介します。`BufferGeometry`とは*一般的に*高速で動きメモリ消費も低く抑えられます。が、設定は少し難しいです。
-
-[ジオメトリの記事](threejs-custom-geometry.html) のおさらいをしましょう。`Geometry`には`Vector3`を設定する必要がありました。これは頂点を表す三次元上の点です。次に`Face3`を設定することで面を定義しました。これはvertexの配列のインデックス情報を使って3つの点を指定することで面を定義しています。光の反射方向などの設定するためにfaceにはnormal(法線)が必要でした。faceに対して1つのnormalを設定することもできますし、vertexに指定して滑らかな面を擬似的に作ることもできました。colorもnormalと同じようにfaceに指定したりvertexに指定したりできました。記事の最後では配列の配列を使ってテクスチャ座標(UV)を設定しました。配列の中の配列の1つが1つのfaceに対応しておりその配列の1つの要素がvertex1つに対応しています。
+Title: Three.js Custom BufferGeometry
+Description: How to make your own BufferGeometry.
+TOC: Custom BufferGeometry
+
+A [previous article](threejs-custom-geometry.html) covered
+how to use `Geometry`. This article is about `BufferGeometry`.
+`BufferGeometry` is *generally* faster to start and uses
+less memory but can be harder to setup.
+
+In [the article on Geometry](threejs-custom-geometry.html) we went over that to use a `Geometry` you supply an
+array of `Vector3` vertices (positions). You then make `Face3` objects specifying
+by index the 3 vertices that make each triangle of the shape you're making. To
+each `Face3` you can specify either a face normal or normals for each individual
+vertex of the face. You can also specify a face color or individual vertex
+colors. Finally you can make a parallel array of arrays of texture coordinates
+(UVs), one array for each face containing an array of UVs, one for each vertex
+of the face.
 
 
 <div class="threejs_center"><img src="resources/threejs-geometry.svg" style="width: 700px"></div>
 <div class="threejs_center"><img src="resources/threejs-geometry.svg" style="width: 700px"></div>
 
 
-`BufferGeometry`は`BufferAttribute`を使います。1つの`BufferAttribute`はジオメトリを作るための1種類のデータに対応しています。vertexの位置情報を格納するための`BufferAttribute`、color情報を格納するための`BufferAttribute`、normal情報を格納するための`BufferAttribute`がそれぞれあります。
+`BufferGeometry` on the other hand uses *named* `BufferAttribute`s.
+Each `BufferAttribute` represents an array of one type of data: positions,
+normals, colors, and uv. Together, the added `BufferAttribute`s represent
+*parallel arrays* of all the data for each vertex.
 
 
 <div class="threejs_center"><img src="resources/threejs-attributes.svg" style="width: 700px"></div>
 <div class="threejs_center"><img src="resources/threejs-attributes.svg" style="width: 700px"></div>
 
 
-上の図では`position`, `normal`, `color`, `uv`それぞれのattribute情報を格納した`BufferAttribute`を表しています。これらは*並列な配列*です。*並列な配列*というのはN番目にあるデータはN番目のvertexに対応しており、それがattributeの数だけあるという意味です。図ではindex=4のattributeがハイライトされています。
-
-<div class="threejs_center"><img src="resources/cube-faces-vertex.svg" style="width: 500px"></div>
-
-上の図のハイライトされたvertexにはこのvertexに接する全ての面のnormalが指定されています。UVを指定するときもすべてのfaceに対して指定する必要があります。これが`Geometry`と`BufferGeometry`の大きな違いです。`BufferGeometry`では情報が共有されることはありません。単一のvertexはこれらの情報の合成として表現されます。
+Above you can see we have 4 attributes: `position`, `normal`, `color`, `uv`.
+They represent *parallel arrays* which means that the Nth set of data in each
+attribute belongs to the same vertex. The vertex at index = 4 is highlighted
+to show that the parallel data across all attributes defines one vertex.
 
 
-実は`Geometry`を使うときはthree.jsが自動的にこのフォーマットに変換しています。`Geometry`が`BufferGeometry`よりメモリを使うのはこの変換のためです。すべての`Vector3`, `Vector2`, `Face3`を`BufferAttribute`配列に変換する際にメモリを使います。`Geometry`は簡単に書けるため便利ですが`BufferGeometry`を使う時にはこれら全ての変換を自分でする必要があります。
+This brings up a point, here's a diagram of a cube with one corner highlighted.
 
 
-簡単な例として`BufferGeometry`を使って立方体を作ってみましょう。立方体を例にするのはvertexがfaceによって共有されているように見えて実は共有されていないからです。この例ではまずすべてのvertexの情報をリストアップして並列の配列に変換して`BufferAttribute`を作り、最後に`BufferGeometry`を作ります。
+<div class="threejs_center"><img src="resources/cube-faces-vertex.svg" style="width: 500px"></div>
 
 
-[以前の記事](threejs-custom-geometry.html)のサンプルコードを使います。`Geometry`を作っていた部分は全て消します。次に立方体に必要な情報をすべてリストアップします。`Geometry`では1つのvertexを複数のfaceで共有できましたが今回は共有できないことに注意してください。つまり1つの立方体を作るために36個のvertexが必要になります。1つの面につき2つの三角形、1つの三角形につき3つのvertex、これが6面あるので36個のvertexが必要になる計算です。
+Thinking about it that single corner needs a different normal for each face of the
+cube. It needs different UVs for each face as well. This points out the biggest difference
+between `Geometry` and `BufferGeometry`. Nothing is shared with `BufferGeometry`.
+A single *vertex* is the combination of all of its parts. If a vertex needs any
+part to be different then it must be a different vertex.
+
+The truth is when you use `Geometry` three.js transforms it into this format.
+That is where the extra memory and time comes from when using `Geometry`. Extra
+memory for all the `Vector3`s, `Vector2`s, `Face3`s and array objects and then
+extra time to translate all of that data into parallel arrays in the form of
+`BufferAttribute`s like above. Sometimes that makes using `Geometry` easier.
+With `BufferGeometry` it is up to us to supply the data already turned into this format.
+
+As a simple example let's make a cube using `BufferGeometry`. A cube is interesting
+because it appears to share vertices at the corners but really
+does not. For our example we'll list out all the vertices with all their data
+and then convert that data into parallel arrays and finally use those to make
+`BufferAttribute`s and add them to a `BufferGeometry`.
+
+Starting with the texture coordinate example from [the previous article](threejs-custom-geometry.html) we've deleted all the code related to setting up
+a `Geometry`. Then we list all the data needed for the cube. Remember again
+that if a vertex has any unique parts it has to be a separate vertex. As such
+to make a cube requires 36 vertices. 2 triangles per face, 3 vertices per triangle,
+6 faces = 36 vertices.
 
 
 ```js
 ```js
 const vertices = [
 const vertices = [
@@ -77,8 +112,7 @@ const vertices = [
 ];
 ];
 ```
 ```
 
 
-次にこれを3つの並列な配列に変換します。
-(訳註:並列な配列*parallel arrays*とは例えば頂点を指定する配列と色を指定する配列があり1つの頂点をレンダリングするために2つの配列の同じインデックスの要素を指定するような使われ方をする配列のことです。次の例ではpositions, normals, uvsの3つの配列が並列の配列として使われています)
+We can then translate all of that into 3 parallel arrays
 
 
 ```js
 ```js
 const positions = [];
 const positions = [];
@@ -91,7 +125,8 @@ for (const vertex of vertices) {
 }
 }
 ```
 ```
 
 
-最後にそれぞれの配列に対して`BufferAttribute`を作り`BufferGeometry`に指定します。
+Finally we can create a `BufferGeometry` and then a `BufferAttribute` for each array
+and add it to the `BufferGeometry`.
 
 
 ```js
 ```js
   const geometry = new THREE.BufferGeometry();
   const geometry = new THREE.BufferGeometry();
@@ -109,16 +144,27 @@ for (const vertex of vertices) {
       new THREE.BufferAttribute(new Float32Array(uvs), uvNumComponents));
       new THREE.BufferAttribute(new Float32Array(uvs), uvNumComponents));
 ```
 ```
 
 
-名前の付け方に注意してください。three.jsで決められている名前以外を指定することはできません(カスタムシェーダーを使用する場合は別です)。`position`, `normal`, `uv`はthree.jsで決められている名前です。ここでは指定していませんが`color`も指定可能です。
+Note that the names are significant. You must name your attributes the names
+that match what three.js expects (unless you are creating a custom shader).
+In this case `position`, `normal`, and `uv`. If you want vertex colors then
+name your attribute `color`.
 
 
-上の例では`positions`, `normals`, `uvs`の3つのJavaScriptのネイティブ配列を作りました。次に`Float32Array`型の[TypedArrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)に変換します。`BufferAttribute`はネイティブ配列ではなくTypedArrayである必要があります。さらにそれぞれの`BufferAttribute`に対して「1つのvertexに対していくつの要素が必要か」を指定する必要があります。例えばpositionやnormalsは3次元なので1つのvertexつき3つの要素を必要とします。UVはテクスチャ上の2次元の点なので2つの要素を必要とします。
+Above we created 3 JavaScript native arrays, `positions`, `normals` and `uvs`.
+We then convert those into
+[TypedArrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)
+of type `Float32Array`. A `BufferAttribute` requires a TypedArray not a native
+array. A `BufferAttribute` also requires you to tell it how many components there
+are per vertex. For the positions and normals we have 3 components per vertex,
+x, y, and z. For the UVs we have 2, u and v.
 
 
 {{{example url="../threejs-custom-buffergeometry-cube.html"}}}
 {{{example url="../threejs-custom-buffergeometry-cube.html"}}}
 
 
-
-かなり大量のデータです。この配列からvertexを選ぶときにはインデックスを使います。1つの三角形は3つのvertexで構成されていて2つの三角形が1つのfaceを作っています。これが6枚で1つの立方体を構成しています。1つのfaceを構成する2つの三角形を作っているvertexは2つが同じデータを持っています。position, normal, UVすべて同じです。そこで重複しているデータを1つ消して1つにして、そのデータを別のインデックスで指定します。
-
-ではまず重複したデータを1つにします。
+That's a lot of data. A small thing we can do is use indices to reference
+the vertices. Looking back at our cube data, each face is made from 2 triangles
+with 3 vertices each, 6 vertices total, but 2 of those vertices are exactly the same;
+The same position, the same normal, and the same uv.
+So, we can remove the matching vertices and then
+reference them by index. First we remove the matching vertices.
 
 
 ```js
 ```js
 const vertices = [
 const vertices = [
@@ -173,7 +219,8 @@ const vertices = [
 ];
 ];
 ```
 ```
 
 
-はい、24個になりました。これに対して36個のインデックスを指定して36個のvertexを作ります。`BufferGeometry.setIndex`により36個のインデックスを使って12個の三角形を作ります。
+So now we have 24 unique vertices. Then we specify 36 indices
+for the 36 vertices we need drawn to make 12 triangles by calling `BufferGeometry.setIndex` with an array of indices.
 
 
 ```js
 ```js
 geometry.setAttribute(
 geometry.setAttribute(
@@ -198,8 +245,10 @@ geometry.setAttribute(
 
 
 {{{example url="../threejs-custom-buffergeometry-cube-indexed.html"}}}
 {{{example url="../threejs-custom-buffergeometry-cube-indexed.html"}}}
 
 
-
-`Geometry`と同じように`BufferGeometry`も[`computeVertexNormals`](BufferGeometry.computeVertexNormals)メソッドを持っています。これは特に指定がない場合に自動的にnormalを計算するメソッドです。ただし`Geometry`の場合と違いvertexがfaceによって共有されていないために`computeVertexNormals`の結果も少し違います。
+Just like `Geometry`, `BufferGeometry` has a [`computeVertexNormals`](BufferGeometry.computeVertexNormals) method for computing normals if you
+are not supplying them. Unlike the `Geometry` version of the same function,
+since positions can not be shared if any other part of a vertex is different
+the results of calling `computeVertexNormals` will be different.
 
 
 <div class="spread">
 <div class="spread">
   <div>
   <div>
@@ -212,11 +261,21 @@ geometry.setAttribute(
   </div>
   </div>
 </div>
 </div>
 
 
-シリンダーで`computeVertexNormals`の違いを比較してみましょう。よく見ると左のシリンダーには縫い目が見えると思います。これはvertexを共有することができないためにUVも異なるためです。ちょっとしたことですが、気になるときは自分でnormalを指定すれば良いだけです。
+Here are 2 cylinders where the normals were created using `computeVertexNormals`.
+If you look closely there is a seam on the left cylinder. This is because there
+is no way to share the vertices at the start and end of the cylinder since they
+require different UVs. Just a small thing to be aware of. The solution is
+to supply your own normals.
 
 
-ネイティブの配列を使う代わりに[TypedArrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)を使うこともできます。TypedArrayは最初に配列の大きさを指定する必要があるため少し面倒です。ネイティブの配列は`push`で追加して`length`で配列の長さを確認することができます。TypedArrayには`push`メソッドがないのであらかじめ用意した配列に注意しながら要素を入れていく必要があります。
+We can also use [TypedArrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) from the start instead of native JavaScript arrays.
+The disadvantage to TypedArrays is you must specify their size up front. Of
+course that's not that large of a burden but with native arrays we can just
+`push` values onto them and look at what size they end up by checking their
+`length` at the end. With TypedArrays there is no push function so we need
+to do our own bookkeeping when adding values to them.
 
 
-この例では最初に大きなデータを使っているので配列の長さを意識することはそれほど大変ではありません。
+In this example knowing the length up front is pretty easy since we're using
+a big block of static data to start.
 
 
 ```js
 ```js
 -const positions = [];
 -const positions = [];
@@ -269,13 +328,19 @@ geometry.setIndex([
 
 
 {{{example url="../threejs-custom-buffergeometry-cube-typedarrays.html"}}}
 {{{example url="../threejs-custom-buffergeometry-cube-typedarrays.html"}}}
 
 
-TypedArrayはプログラムが走っている状態でvertexの編集をしたいときに便利です。
+A good reason to use typedarrays is if you want to dynamically update any
+part of the vertices.
 
 
-良い例が思いつかないのでとりあえずメッシュの四角形が出たり入ったりする球体を作ってみます。
+I couldn't think of a really good example of dynamically updating the vertices
+so I decided to make a sphere and move each quad in and out from the center. Hopefully
+it's a useful example.
 
 
-球体の位置とindexを生成するコードです。四角形の中でvertexを共有していますが四角形と四角形でvertexを共有することはありません。共有してしまうと1つの四角形が出たり入ったりするたびに隣の四角形が移動してしまいます。今回は別々に移動させたいのでそうしています。
+Here's the code to generate positions and indices for a sphere. The code
+is sharing vertices within a quad but it's not sharing vertices between
+quads because we want to be able to move each quad separately.
 
 
-面倒なので3つの`Object3D`階層を用意して球体のvertexを計算します。くわしくは[たくさんのオブジェクトを最適化するこの記事](threejs-optimize-lots-of-objects.html)をご覧ください。
+Because I'm lazy I used a small hierarchy of 3 `Object3D` objects to compute
+sphere points. How this works is explained in [the article on optimizing lots of objects](threejs-optimize-lots-of-objects.html).
 
 
 ```js
 ```js
 function makeSpherePositions(segmentsAround, segmentsDown) {
 function makeSpherePositions(segmentsAround, segmentsDown) {
@@ -329,20 +394,22 @@ function makeSpherePositions(segmentsAround, segmentsDown) {
 }
 }
 ```
 ```
 
 
-こんな感じです。
+We can then call it like this
 
 
 ```js
 ```js
 const segmentsAround = 24;
 const segmentsAround = 24;
 const segmentsDown = 16;
 const segmentsDown = 16;
 const {positions, indices} = makeSpherePositions(segmentsAround, segmentsDown);
 const {positions, indices} = makeSpherePositions(segmentsAround, segmentsDown);
 ```
 ```
-returnされているpositionは単位球(半径が1の球体)なのでそのままこのデータをnormalに使えます。
+
+Because positions returned are unit sphere positions so they are exactly the same
+values we need for normals so we can just duplicated them for the normals.
 
 
 ```js
 ```js
 const normals = positions.slice();
 const normals = positions.slice();
 ```
 ```
 
 
-attributeも設定しましょう。
+And then we setup the attributes like before
 
 
 ```js
 ```js
 const geometry = new THREE.BufferGeometry();
 const geometry = new THREE.BufferGeometry();
@@ -360,7 +427,11 @@ geometry.setAttribute(
 geometry.setIndex(indices);
 geometry.setIndex(indices);
 ```
 ```
 
 
-position attributeに対する参照を保存しています。dynamicに指定しているところも注意が必要です。これはTHREE.jsに「これからこのattributeは変更が加えられる」ことを教えます。renderループではpositionを毎度アップデートします。
+I've highlighted a few differences. We save a reference to the position attribute.
+We also mark it as dynamic. This is a hint to THREE.js that we're going to be changing
+the contents of the attribute often.
+
+In our render loop we update the positions based off their normals every frame.
 
 
 ```js
 ```js
 const temp = new THREE.Vector3();
 const temp = new THREE.Vector3();
@@ -380,11 +451,14 @@ for (let i = 0; i < positions.length; i += 3) {
 positionAttribute.needsUpdate = true;
 positionAttribute.needsUpdate = true;
 ```
 ```
 
 
-最後に`positionAttribute.needsUpdate`を設定してTHREE.jsに変更が必要であることを伝えます。
+And we set `positionAttribute.needsUpdate` to tell THREE.js to use our changes.
 
 
 {{{example url="../threejs-custom-buffergeometry-dynamic.html"}}}
 {{{example url="../threejs-custom-buffergeometry-dynamic.html"}}}
 
 
-`BufferGeometry`を作って`BufferAttribute`をアップデートする方法を紹介しました。`BufferAttribute`を使うか`Geometry`はケースバイケースです。
+I hope these were useful examples of how to use `BufferGeometry` directly to
+make your own geometry and how to dynamically update the contents of a
+`BufferAttribute`. Which you use, `Geometry` or `BufferGeometry`, really
+depends on your needs.
 
 
 <canvas id="c"></canvas>
 <canvas id="c"></canvas>
 <script type="module" src="resources/threejs-custom-buffergeometry.js"></script>
 <script type="module" src="resources/threejs-custom-buffergeometry.js"></script>