three.js BufferGeometry入門 Part2

前回 : three.js BufferGeometry入門 Part1

前回はBufferGeometryで6個の頂点から3角形を2枚作り4角形を描画した。4角形を描画するのに6個頂点を用意しなくちゃいけないのはメモリの無駄使いだし単純に面倒でもある。インデックスバッファを使えば4角形を作るのに4個の頂点を用意すればよくなるので、その使い方を解説していく。wgld.orgのインデックスバッファによる描画をさくっと読んでおくと理解が250%深まる。というか読んだ前提で解説する。

インデックスバッファで4角形を作る

前回使ったmain01.jsのプログラムから変更点だけ解説する。

まずは4つの頂点を設定し、position attributeを追加する。
main02.js

// ジオメトリの作成
var geometry = new THREE.BufferGeometry();
var numPoints = 4; // ジオメトリを構成する点の数
// 頂点の設定
var positions = new THREE.Float32BufferAttribute(numPoints * 3, 3);
// 四隅に頂点を配置
positions.setXYZ(0, -1.0, 1.0, 0);
positions.setXYZ(1, -1.0, -1.0, 0);
positions.setXYZ(2, 1.0, -1.0, 0);
positions.setXYZ(3, 1.0, 1.0, 0);
// position attributeを追加
geometry.addAttribute("position", positions);

次にインデックスバッファを設定する。

// インデックスの設定
var indices = [
0, 1, 2, // 一枚目の三角形
2, 3, 0 // 二枚目の三角形
];
geometry.setIndex(new THREE.Uint16BufferAttribute(indices, 1));

これで4角形が作れる。超簡単。

インデックスバッファは簡単に言うと、3角形を作る時にどの頂点を使うかをWebGL側に指定するもの。上の例では(0番目, 1番目, 2番目)の頂点で1枚目の3角形を、(2番目, 3番目, 0番目)の頂点で2枚目の3角形を作るように指定している。geometryにインデックスバッファを設定するにはaddAttribute()ではなくsetIndex()を使う。インデックスは頂点とは違い整数データなのでTypedArrayにはUint16を使う。また、インデックスバッファは1つの値で意味をなすのでitemSizeは1になる。

めちゃくちゃざっくりだけどインデックスバッファの解説は以上。

three.js BufferGeometry入門 Part1

three.jsのBufferGeometryクラスの使い方を解説していく。three.js r84を使用。
この記事で使うプログラムはこちら

GeometryとBufferGeometry

three.jsにはGeometryというジオメトリを表すクラスと、このGeometryクラスを継承してより具体的なジオメトリを表すBoxGeometrySphereGeometryなどがある。シンプルなシーンの作成ならこれらを使うが、BufferGeometryクラスを使うとより複雑な処理を書くことができる。具体的にどんなことができるかは公式Examplesのwebgl/advancedの項目を見るのが手っ取り早い。

素のwebglの知識が全くない状態だとBufferGeometryの使いどころとか感覚がつかめないと思う。まずはwgld.orgの「ブラウザの準備」〜「インデックスバッファによる描画」あたりまで読んでおくと良い。BufferGeometryを使う分には素のwebglが書ける状態にまで持っていく必要はない。テキストを読んでなるほどと思えればおk。この記事は上記の記事を読んだ前提で話を進める。

BufferGeometryで4角形を作る

今のwebglでは点、線、3角形しか作ることができない。4角形を作るには3角形を2つ用意する必要がある。

main01.js

// シーンの作成
var scene = new THREE.Scene();
// カメラの作成
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 10);
// レンダラーの作成
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0x00142b);
document.getElementById("CanvasContainer").appendChild(renderer.domElement);
// ジオメトリの作成
var geometry = new THREE.BufferGeometry();
var numPoints = 6; // ジオメトリを構成する点の数
// 頂点の設定
var positions = new THREE.Float32BufferAttribute(numPoints * 3, 3);
// 一枚目の三角形
positions.setXYZ(0, -1.0, 1.0, 0);
positions.setXYZ(1, -1.0, -1.0, 0);
positions.setXYZ(2, 1.0, -1.0, 0);
// 二枚目の三角形
positions.setXYZ(3, 1.0, -1.0, 0);
positions.setXYZ(4, 1.0, 1.0, 0);
positions.setXYZ(5, -1.0, 1.0, 0);
// position attributeを追加
geometry.addAttribute("position", positions);
// マテリアルの作成
var material = new THREE.MeshBasicMaterial({color: 0xffffff});
// メッシュの作成
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// 描画開始
render();
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}

BufferGeometryはBufferAttributeクラスで作成したattributeをaddAttribute()で追加するという形で使う。THREE.Float32BufferAttributeとかはBufferAttributeクラスを各TypedArrayで作成しやすくした便利クラス。使い方はソース読むのがわかりやすい。
https://github.com/mrdoob/three.js/blob/master/src/core/BufferAttribute.js

function Float32BufferAttribute( array, itemSize ) {
BufferAttribute.call( this, new Float32Array( array ), itemSize );
}

ここの引数にあるarrayは配列そのものであったり配列の要素数のことだったりする。上のプログラムでは要素数を渡している。

// 頂点の設定
var positions = new THREE.Float32BufferAttribute(numPoints * 3, 3);

numPoints * 3としているのは1個の頂点には(x, y, z)の3つの値があるから頂点数 * (x, y, z)という意味。itemSizeは追加したいattributeがいくつの数値の集合で意味をなすのかを表す。position attributeは(x, y, z)の3つで1つの頂点を表すのでitemSizeが3。ちなみにcolor attributeは(r, g, b)のつもりならitemSizeは3で、(r, g, b, a)なら4になる。こんな感じに1次元配列でattributeを扱うのでBufferAttributeのsetXYZ()メソッドとかは直感的に配列にアクセスしてx, y, zを設定できるように内部でうまいことitemSize使ってる。

setXYZ: function ( index, x, y, z ) {
index *= this.itemSize;
this.array[ index + 0 ] = x;
this.array[ index + 1 ] = y;
this.array[ index + 2 ] = z;
return this;
},

threejs公式Exampleのこれはキューブ状に点をバラバラに配置して3角形を大量に描画している。positionの他にcolor attributeとnormal attributeも設定している。

Part1は終了。次回はインデックスバッファを使って4つの頂点で4角形を作る解説をする。

次回 : three.js BufferGeometry入門 Part2

ブログ環境変えました

はてなブログでProcessing中毒者の嘔吐物っていうブログやってたけどいろいろ好き勝手にいじりたいのでHexoに移行した。主にクリエイティブコーディング、Web関連の技術ネタとたまにポエムを書いていきたい。ある程度記事が溜まったらテーマも一から作る予定。