|
@@ -22,6 +22,8 @@ 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.
|
|
`BufferGeometry` on the other hand uses *named* `BufferAttribute`s.
|
|
Each `BufferAttribute` represents an array of one type of data: positions,
|
|
Each `BufferAttribute` represents an array of one type of data: positions,
|
|
normals, colors, and uv. Together, the added `BufferAttribute`s represent
|
|
normals, colors, and uv. Together, the added `BufferAttribute`s represent
|
|
@@ -29,6 +31,8 @@ normals, colors, and uv. Together, the added `BufferAttribute`s represent
|
|
|
|
|
|
<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がハイライトされています。
|
|
|
|
+
|
|
Above you can see we have 4 attributes: `position`, `normal`, `color`, `uv`.
|
|
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
|
|
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
|
|
attribute belongs to the same vertex. The vertex at index = 4 is highlighted
|
|
@@ -38,12 +42,17 @@ This brings up a point, here's a diagram of a cube with one corner highlighted.
|
|
|
|
|
|
<div class="threejs_center"><img src="resources/cube-faces-vertex.svg" style="width: 500px"></div>
|
|
<div class="threejs_center"><img src="resources/cube-faces-vertex.svg" style="width: 500px"></div>
|
|
|
|
|
|
|
|
+上の図のハイライトされたvertexにはこのvertexに接する全ての面のnormalが指定されています。UVを指定するときもすべてのfaceに対して指定する必要があります。これが`Geometry`と`BufferGeometry`の大きな違いです。`BufferGeometry`では情報が共有されることはありません。単一のvertexはこれらの情報の合成として表現されます。
|
|
|
|
+
|
|
Thinking about it that single corner needs a different normal for each face of the
|
|
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
|
|
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`.
|
|
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
|
|
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.
|
|
part to be different then it must be a different vertex.
|
|
|
|
|
|
|
|
+
|
|
|
|
+実は`Geometry`を使うときはthree.jsが自動的にこのフォーマットに変換しています。`Geometry`が`BufferGeometry`よりメモリを使うのはこの変換のためです。すべての`Vector3`, `Vector2`, `Face3`を`BufferAttribute`配列に変換する際にメモリを使います。`Geometry`は簡単に書けるため便利ですが`BufferGeometry`を使う時にはこれら全ての変換を自分でする必要があります。
|
|
|
|
+
|
|
The truth is when you use `Geometry` three.js transforms it into this format.
|
|
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
|
|
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
|
|
memory for all the `Vector3`s, `Vector2`s, `Face3`s and array objects and then
|
|
@@ -51,12 +60,16 @@ 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.
|
|
`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.
|
|
With `BufferGeometry` it is up to us to supply the data already turned into this format.
|
|
|
|
|
|
|
|
+簡単な例として`BufferGeometry`を使って立方体を作ってみましょう。立方体を例にするのはvertexがfaceによって共有されているように見えて実は共有されていないからです。この例ではまずすべてのvertexの情報をリストアップして並列の配列に変換して`BufferAttribute`を作り、最後に`BufferGeometry`を作ります。
|
|
|
|
+
|
|
As a simple example let's make a cube using `BufferGeometry`. A cube is interesting
|
|
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
|
|
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
|
|
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
|
|
and then convert that data into parallel arrays and finally use those to make
|
|
`BufferAttribute`s and add them to a `BufferGeometry`.
|
|
`BufferAttribute`s and add them to a `BufferGeometry`.
|
|
|
|
|
|
|
|
+[以前の記事](threejs-custom-geometry.html)のサンプルコードを使います。`Geometry`を作っていた部分は全て消します。次に立方体に必要な情報をすべてリストアップします。`Geometry`では1つのvertexを複数のfaceで共有できましたが今回は共有できないことに注意してください。つまり1つの立方体を作るために36個のvertexが必要になります。1つの面につき2つの三角形、1つの三角形につき3つのvertex、これが6面あるので36個のvertexが必要になる計算です。
|
|
|
|
+
|
|
Starting with the texture coordinate example from [the previous article](threejs-custom-geometry.html) we've deleted all the code related to setting up
|
|
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
|
|
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
|
|
that if a vertex has any unique parts it has to be a separate vertex. As such
|
|
@@ -116,6 +129,9 @@ const vertices = [
|
|
];
|
|
];
|
|
```
|
|
```
|
|
|
|
|
|
|
|
+次にこれを3つの並列な配列に変換します。
|
|
|
|
+(訳註:並列な配列*parallel arrays*とは例えば頂点を指定する配列と色を指定する配列があり1つの頂点をレンダリングするために2つの配列の同じインデックスの要素を指定するような使われ方をする配列のことです。次の例ではpositions, normals, uvsの3つの配列が並列の配列として使われています)
|
|
|
|
+
|
|
We can then translate all of that into 3 parallel arrays
|
|
We can then translate all of that into 3 parallel arrays
|
|
|
|
|
|
```js
|
|
```js
|
|
@@ -129,8 +145,7 @@ for (const vertex of vertices) {
|
|
}
|
|
}
|
|
```
|
|
```
|
|
|
|
|
|
-Finally we can create a `BufferGeometry` and then a `BufferAttribute` for each array
|
|
|
|
-and add it to the `BufferGeometry`.
|
|
|
|
|
|
+最後にそれぞれの配列に対して`BufferAttribute`を作り`BufferGeometry`に指定します。
|
|
|
|
|
|
```js
|
|
```js
|
|
const geometry = new THREE.BufferGeometry();
|
|
const geometry = new THREE.BufferGeometry();
|
|
@@ -148,11 +163,15 @@ and add it to the `BufferGeometry`.
|
|
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
|
|
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).
|
|
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
|
|
In this case `position`, `normal`, and `uv`. If you want vertex colors then
|
|
name your attribute `color`.
|
|
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`.
|
|
Above we created 3 JavaScript native arrays, `positions`, `normals` and `uvs`.
|
|
We then convert those into
|
|
We then convert those into
|
|
[TypedArrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)
|
|
[TypedArrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)
|
|
@@ -163,6 +182,12 @@ 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
|
|
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
|
|
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;
|
|
with 3 vertices each, 6 vertices total, but 2 of those vertices are exactly the same;
|
|
@@ -223,6 +248,8 @@ const vertices = [
|
|
];
|
|
];
|
|
```
|
|
```
|
|
|
|
|
|
|
|
+はい、24個になりました。これに対して36個のインデックスを指定して36個のvertexを作ります。`BufferGeometry.setIndex`により36個のインデックスを使って12個の三角形を作ります。
|
|
|
|
+
|
|
So now we have 24 unique vertices. Then we specify 36 indices
|
|
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.
|
|
for the 36 vertices we need drawn to make 12 triangles by calling `BufferGeometry.setIndex` with an array of indices.
|
|
|
|
|
|
@@ -249,6 +276,9 @@ 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
|
|
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,
|
|
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
|
|
since positions can not be shared if any other part of a vertex is different
|
|
@@ -265,12 +295,16 @@ the results of calling `computeVertexNormals` will be different.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
+シリンダーで`computeVertexNormals`の違いを比較してみましょう。よく見ると左のシリンダーには縫い目が見えると思います。これはvertexを共有することができないためにUVも異なるためです。ちょっとしたことですが、気になるときは自分でnormalを指定すれば良いだけです。
|
|
|
|
+
|
|
Here are 2 cylinders where the normals were created using `computeVertexNormals`.
|
|
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
|
|
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
|
|
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
|
|
require different UVs. Just a small thing to be aware of. The solution is
|
|
to supply your own normals.
|
|
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.
|
|
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
|
|
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
|
|
course that's not that large of a burden but with native arrays we can just
|
|
@@ -278,6 +312,8 @@ course that's not that large of a burden but with native arrays we can just
|
|
`length` at the end. With TypedArrays there is no push function so we need
|
|
`length` at the end. With TypedArrays there is no push function so we need
|
|
to do our own bookkeeping when adding values to them.
|
|
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
|
|
In this example knowing the length up front is pretty easy since we're using
|
|
a big block of static data to start.
|
|
a big block of static data to start.
|
|
|
|
|
|
@@ -332,6 +368,14 @@ geometry.setIndex([
|
|
|
|
|
|
{{{example url="../threejs-custom-buffergeometry-cube-typedarrays.html"}}}
|
|
{{{example url="../threejs-custom-buffergeometry-cube-typedarrays.html"}}}
|
|
|
|
|
|
|
|
+TypedArrayはプログラムが走っている状態でvertexの編集をしたいときに便利です。
|
|
|
|
+
|
|
|
|
+良い例が思いつかないのでとりあえずメッシュの四角形が出たり入ったりする球体を作ってみます。
|
|
|
|
+
|
|
|
|
+球体の位置とindexを生成するコードです。四角形の中でvertexを共有していますが四角形と四角形でvertexを共有することはありません。共有してしまうと1つの四角形が出たり入ったりするたびに隣の四角形が移動してしまいます。今回は別々に移動させたいのでそうしています。
|
|
|
|
+
|
|
|
|
+面倒なので3つの`Object3D`階層を用意して球体のvertexを計算します。くわしくは[たくさんのオブジェクトを最適化するこの記事](threejs-optimize-lots-of-objects.html)をご覧ください。
|
|
|
|
+
|
|
A good reason to use typedarrays is if you want to dynamically update any
|
|
A good reason to use typedarrays is if you want to dynamically update any
|
|
part of the vertices.
|
|
part of the vertices.
|
|
|
|
|
|
@@ -398,6 +442,8 @@ function makeSpherePositions(segmentsAround, segmentsDown) {
|
|
}
|
|
}
|
|
```
|
|
```
|
|
|
|
|
|
|
|
+こんな感じです。
|
|
|
|
+
|
|
We can then call it like this
|
|
We can then call it like this
|
|
|
|
|
|
```js
|
|
```js
|
|
@@ -406,6 +452,8 @@ 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
|
|
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.
|
|
values we need for normals so we can just duplicated them for the normals.
|
|
|
|
|
|
@@ -413,6 +461,8 @@ values we need for normals so we can just duplicated them for the normals.
|
|
const normals = positions.slice();
|
|
const normals = positions.slice();
|
|
```
|
|
```
|
|
|
|
|
|
|
|
+attributeも設定しましょう。
|
|
|
|
+
|
|
And then we setup the attributes like before
|
|
And then we setup the attributes like before
|
|
|
|
|
|
```js
|
|
```js
|
|
@@ -431,6 +481,8 @@ 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.
|
|
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
|
|
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.
|
|
the contents of the attribute often.
|
|
@@ -455,10 +507,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.
|
|
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
|
|
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
|
|
make your own geometry and how to dynamically update the contents of a
|
|
`BufferAttribute`. Which you use, `Geometry` or `BufferGeometry`, really
|
|
`BufferAttribute`. Which you use, `Geometry` or `BufferGeometry`, really
|