Three.js による頂点データの取り込みと描画 (イトカワの形状データ)
Three.js とは、HTML5で新しく登場する canvas 要素に Javascript を利用して描画する際に、便利なライブラリとして知られています。 これまで本サイトでは、canvas 要素に描画するデータを GPU 上から直接利用する WebGL と呼ばれるAPIのライブラリとして、Three.jsを利用しています。 本稿では、JAXAが公開している小惑星イトカワの形状データを利用して、ウェブ上でイトカワの3次元的に描画すること行います。 ある程度リアルな形状を実現しようとすると頂点データが膨大となり、マウス操作に対する応答などのインタラクティブ性が落ちるのはないかと思われますが、WebGLを利用することでそんな心配はありません。 WebGLでは、頂点座標などの形状を決めるデータ(これが莫大)を予め GPU に送り込んでおき、 オブジェクトの姿勢やカメラ視点、光源などの各フレームごとに変化するデータのみを毎フレームごと加えて描画するため、 快適なインタラクティブ性を実現することができます。頂点座標データ量 70MB(面の数:786432個) でもカクカクしません。 これは、WebGLを利用することの最大のメリットです。 ただし読み込み時間は、頂点データ量に比例して長くなります。
実行結果
WebGLが実行可能な環境で実行ページ(面の数:49152個(読み込み時間:2秒))をご覧下さい。 下記の図はデモ画面です。
以下の図はデモ画面です → 実行ページこちら
小惑星イトカワの頂点データ
本稿で利用させて頂いた小惑星イトカワの形状データは「Gaskell 形状モデル(Hayabusa Project Science Data Archive : JAXA)」のTRI形式のデータです。 TRI形式は、1つの三角形を構成する3つの頂点座標と色のセットで構成されます。
点1のx 点1のy 点1のz 点2のx 点2のy 点2のz 点3のx 点3のy 点3のz 色 点1のx 点1のy 点1のz 点2のx 点2のy 点2のz 点3のx 点3のy 点3のz 色 点1のx 点1のy 点1のz 点2のx 点2のy 点2のz 点3のx 点3のy 点3のz 色 ・・・
というように、1行ごとに10個の情報がスペース区切りで配置され、次の行には次の三角形に関する情報となります。 TRI形式のデータは具体的に次のような形式になっています。
-0.150880 0.077950 0.076390 -0.150770 0.076760 0.077080 -0.148510 0.077040 0.077720 0xffffff -0.150770 0.076760 0.077080 -0.148330 0.075750 0.078100 -0.148510 0.077040 0.077720 0xffffff -0.150770 0.076760 0.077080 -0.150520 0.075450 0.077360 -0.148330 0.075750 0.078100 0xffffff ・・・
ただし、本データは色は「白」だけなので、本稿では利用しません。 また、一般的にコンピュータグラフィックで頂点データから形状をモデリングする際に、各面(三角形)に対する法線ベクトルが必要になるため、 三角形の頂点データから法線ベクトルを計算します。
//3点で形成される三角形の位置ベクトルから法線ベクトルを計算する関数 function Normal( v1, v2, v3 ){ var vx = (v1.y - v3.y) * (v2.z - v3.z) - (v1.z - v3.z) * (v2.y - v3.y); var vy = (v1.z - v3.z) * (v2.x - v3.x) - (v1.x - v3.x) * (v2.z - v3.z); var vz = (v1.x - v3.x) * (v2.y - v3.y) - (v1.y - v3.y) * (v2.x - v3.x); var va = Math.sqrt( Math.pow(vx,2) +Math.pow(vy,2)+Math.pow(vz,2)); var v = {x:vx/va, y:vy/va, z:vz/va}; //規格化する return v; }
Three.jsを利用して三角形のポリゴンを描画する際にもこの法線ベクトルを使用します。 これでイトカワを描画するためのデータは揃いました。 あとはThree.jsのポリゴンを次のようにして描画します。
var itokawa; function initObject(){ //「data」は 「itokawa_f0049152.js」で定義されるイトカワの頂点データ var lines = data.split("\n"); //三角形データごとに分割(「\n」データ区切り文字) var geom = new THREE.Geometry();//形状の設定 for (var i=0; i<lines.length; i++) { var vertexes = lines[i].split(" ");//三角形の頂点の各座標 3点×3座標 var p1 = {x:vertexes[0], y:vertexes[1], z:vertexes[2]}; var p2 = {x:vertexes[3], y:vertexes[4], z:vertexes[5]}; var p3 = {x:vertexes[6], y:vertexes[7], z:vertexes[8]}; var n = Normal( p1, p2, p3 ); var v1 = new THREE.Vector3(p1.x, p1.y, p1.z); var v2 = new THREE.Vector3(p2.x, p2.y, p2.z); var v3 = new THREE.Vector3(p3.x, p3.y, p3.z); geom.vertices.push(new THREE.Vertex(v1)); geom.vertices.push(new THREE.Vertex(v2)); geom.vertices.push(new THREE.Vertex(v3)); var face = new THREE.Face3( 3*i, 3*i+1, 3*i+2 ); var faceNormal = new THREE.Vector3( n.x, n.y, n.z ); face.normal = faceNormal; geom.faces.push( face ); } var material = new THREE.MeshLambertMaterial({color: 0xffffff, ambient:0xffffff}); //材質の設定 itokawa = new THREE.Mesh( geom, material); //イトカワ itokawa.scale = new THREE.Vector3( 100, 100, 100 ); //イトカワのスケールを等方的に100倍する scene.add(itokawa); itokawa.position.set(0,0,0); }
注意
Javascript の標準機能だけで、スペース区切りの外部データを取り込む方法がわからなかったので、 本稿では予め「itokawa_f0049152.js」で、「data」という文字列を用意してそれを分割することで利用することにしました。
var data = "-0.150880 0.077950 0.076390 -0.150770 0.076760 0.077080 -0.148510 0.077040 0.077720 0xffffff\ \n-0.150770 0.076760 0.077080 -0.148330 0.075750 0.078100 -0.148510 0.077040 0.077720 0xffffff\ \n-0.150770 0.076760 0.077080 -0.150520 0.075450 0.077360 -0.148330 0.075750 0.078100 0xffffff\ ・・・ \n0.132150 0.063590 -0.048480 0.129540 0.063900 -0.047790 0.131900 0.064090 -0.047790 0xffffff";
Javascriptにて文字列を扱う場合、改行があるとまずいので「\」で改行をエスケープし「\n」を行ごとにいれこむことで、頂点データ全体を一つの文字列として扱います。 その後、文字列を分割して Javascript の配列として扱います。
参考ページ
■ HTML5による物理シミュレーション環境の構築 ~WebGLライブラリThree.js 入門(1/3)~
■ HTML5による物理シミュレーション環境の構築 ~WebGLライブラリThree.js 入門(2/3)~
■ HTML5による物理シミュレーション環境の構築 ~WebGLライブラリThree.js 入門(3/3)~