Skip to main content

Webページで3Dグラフィックを表示する

今回はBlenderで自作した3DグラフィックをWebページ上で表示する方法を紹介いたします。

Blenderでグラフィックを作成する様子:(クリックすると拡大します)

design_time

Webページで表示する様子:

run_time

実際にWeb上で表示した動画のページはこちらです
(Chrome、Firefox最新版、IE11以上のブラウザをご利用ください)

データ処理の流れ

3Dグラフィックを表示する際に利用する技術はHTML5のWebGLです。Blenderで3Dグラフィックのオブジェクトを作成し、ChromeやIE11でWebGLを利用すれば、グラフィックをWebページで表示できます。

flow

Blenderでモデリングしたオブジェクトを、さまざまなファイル形式で外へのエクスポートが可能です。今回では平文(PlainTextObj)であるObjフォーマットを採用します。(Objフォーマットについてこちらの英語のページをご参照ください)

モデリングとObjエクスポート

3DグラフィックをBlenderでモデリングした後に、Objファイルフォーマットとして外にエクスポートできます。

エクスポートしたいオブジェクトを選択し、File->Export->Wavefront (.obj)をクリックします。左側にエクスポートの設定画面が表示され、以下の設定を行います。

export_settings

1. Selection Onlyを選択し、現在選択されているオブジェクトのみをエクスポート対象とします。

2. Apply Modifiersを選択し、Mirror、SubdivisionなどのModifierが設定されている場合、すべてModifierを適用してからエクスポートするようにします。

3. Write Normalsを選択し、法線データもエクスポートします。

4. Triangulate Facesを選択し、頂点データを三角形に揃えます。

5. エクスポートしたグラフィックが画面に表示された時、サイズが大きすぎることがあります。その場合このScaleの値をより小さく(0.1~1)設定し、ちょうどいいサイズに調整することが可能です。

設定が完了したらファイル名とパスも指定して、エクスポートを実行します。

(この文書でモデリングしたObjファイルは、こちらです)

Objファイル→Modelファイルに変換

Objファイルは平文(PlainText)で頂点、法線などのデータを記録するファイルです。単にこのファイルから頂点データをWebGLに渡しても3Dグラフィックを再生できますが、テキストの解析に時間がかかりますので、プログラムの初期化性能が落ちます。

そのために、事前にObjファイルを解析し、表示用のバイナリデータを用意しファイルに保存します。この保存されたファイルはModelファイルと言い、ネコ技術のオリジナルファイルフォーマットです。ネコ技術はObjファイルからModelファイルに変換するプログラムを実装しましたので、無償で提供いたします。

ダウンロードはこちらです。(EXEファイルを含まれていますので、ダウンロードの際に警告が出るかことがありますがこのサイトが作ったソフトなので安全です

変換プログラムはコマンドベースのプログラムで、利用方法は以下の通りです:

Obj2Model.exe <入力Objファイルのパス> <出力Modelファイルのパス>

cmd.exeを起動し、画面でコマンドを実行します。入力Objファイルを正しく解析した場合、指定されたパスにModelファイルが生成されます。

D:\Obj2Model\Debug>Obj2Model.exe ...\feifei.obj ...\model\cat.mod
reading obj file...
process indexes...
writing mod file...

 vertexs:           29856
 normals:           29856
 texcoords:         0

 vertex buffer:     358,272
 normal buffer:     358,272
 texcoord buffer:   0

 total bytes:       716,556

done.

パス…\model\cat.mod を開いて、cat.modファイルが確かに存在することを確認します。

WebGLでModelファイルを画面に出力

WebGLについて基本的な利用方法は他の書籍、資料などをご参照ください。ネコ技術が作成したJavaScriptプログラムとHTMLの一式を、こちらからダウンロードすることが可能です。以下はプログラムのキーの部分のみを紹介いたします。

Webサイトのファイル構成

\
  cat.html                3Dグラフィック表示用メインHTML 
js\
  main.js                 WebGLの共通初期化処理
  model.js                Modelファイルを読み込み、画面に出力するプログラム
  glMatrix-0.9.5.min.js   行列の計算ライブラリ(Third-party)
model\
  cat.mod                 ObjファイルからコンバートしたModelファイル 

main.jsとmodel.jsはネコ技術が作成したWebGLの共通JavaScriptです。特にmodel.jsは、上記Objファイルから転換されたModelファイルを読み込み、WebGLによって画面に描画するプログラムの一式を実装しています。

メインHTML

メインHTMLからJavaScriptファイルを参照します。

<!DOCTYPE html>
<html>
<head>
  <script type="text/javascript" src="js/glMatrix-0.9.5.min.js"></script>
  <script src="js/main.js"></script>
  <script src="js/model.js"></script>
</head>
...
</html>

WebGLの準備

WebGLによって3Dグラフィック表示するため、Webページで表示用領域を用意する必要があります。HTML5のCanvasタグを利用します。

<body>
...
 <canvas id="glcanvas" width="640" height="480">
   該当ブラウザはHTML5のCanvasをサポートしていません。
 </canvas>
...
</body>

もしCanvasをサポートしないブラウザを利用した場合、「サポートしない」というメッセージが表示されます。Canvasのidを「glcanvas」と設定し、JavaScript側はこのidを利用します。

ライティング

WebGLはOpenGLと違い、内部にライティングと照明のAPIを用意していません。シェーダプログラムで自分のライティング計算プログラムを書く必要があります。但し簡単に3Dのように見えるライティング計算はそれほど難しくありません。

lighting

WebGLは頂点シェーダプログラムとフラグメントシェーダプログラムを、両方とも用意する必要があります。

頂点シェーダプログラム(GLSL言語):

<script id="shader-vs" type="x-shader/x-vertex">
  attribute vec3 aVertexPosition;  // modelファイルからの頂点データ
  attribute vec3 aVertexNormal;    // modelファイルからの法線データ

  uniform mat4 uNormalMatrix;      // 法線変換行列
  uniform mat4 uMVMatrix;          // 共通オブジェクト変換行列
  uniform mat4 uPMatrix;           // 共通投影変換行列
  uniform vec4 ambientLight;       // オブジェクトの環境反射色
  varying vec4 vLighting;          // 計算されたライティングの色
 
  void main(void) {
    // 現在処理中の頂点位置を行列によって変換処理を行う
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);

    // 光源の色(RGB)
    vec3 directionalLightColor = vec3(0.5, 0.5, 0.5);
    // 光源の位置(手前右側)
    vec3 directionalVector = vec3(0.85, 0.8, 0.75);
    // オブジェクト法線の変換
    vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
    // 光源と変換した法線の内積 (つまり頂点法線が光源に向くほど、明るくなる)
    float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);

    // 内積を乗って光の色とオブジェクトの環境反射色を足して、最終の色を計算する
    // vLighting に保存した色はフラグメントシェーダに自動的に渡される
    vLighting = vec4(ambientLight.rgb + (directionalLightColor * directional), 1.0);
  }
</script>

フラグメントシェーダプログラム(GLSL言語):

<script id="shader-fs" type="x-shader/x-fragment">
  varying mediump vec4 vLighting;

  void main(void) {
    gl_FragColor = vLighting;
  }
</script>

フラグメントシェーダでは特に計算するものはありませんので、頂点シェーダから渡されたvLightingの色をそのままPixelに設定します。

Modelファイルの準備

window.onloadイベントより、プログラムの初期化処理を行います。

model.jsファイルに以下のファンクションを用意しています。

  • modelManager.loadModel – Modelファイルを読み込んで、modelオブジェクトを作成します
  • bindModelBuffer – loadModelによって作成されたオブジェクトをWebGLのバッファーに配置します
  • drawModel – modelオブジェクトをWebGLのAPIを利用して3D描画処理を行います

model.jsを参照に設定した場合、デフォルトでmodelManagerというグローバル変数があります。modelManager.loadModelファンクションを利用し、上記で作成したcat.modファイルを読み込みます。パスはcat.htmlファイルからの相対パスです。

window.onload = function () {
  modelManager.loadModel("model/cat.mod", function (model) {

  // WebGL初期化処理
  start();

  // modelの色を設定する
  model.color = [0.3, 0.3, 0.3, 1.0];

  // WebGLのバッファーにBindする
  bindModelBuffer(model);

  // modelオブジェクトをグローバル変数に設定
  window.model = model;

  // 描画開始
  drawScene();
  });
};

loadModelの二つ目のパラメータは、Modelファイルを正しく読み取れた場合に呼び出されるファンクションです。このファンクションで、引き続きWebGLの初期化処理を行います。WebGLに関する共通初期化処理は、main.jsのstartファンクションに実装しています。

WebGLの初期化処理

main.jsのstartファンクションより、initSceneファンクションが呼び出されます。このファンクションで、WebGL共通初期化以外、HTML毎の初期化処理を行うことが可能です。

function initScene() {
  gl.viewport(0, 0, canvas.width, canvas.height);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
 
  // 深さテストを有効に設定
  gl.enable(gl.DEPTH_TEST);
  gl.depthFunc(gl.LEQUAL);
}

すべての処理化処理を行ってから、drawScene()を呼び出して描画処理を始めます。

描画処理

// 動画のフレーム処理
function frame() {

  // 自動回転
  if (autoRotate) {
    angle += 0.01;
    if (angle > Math.PI * 2) angle -= Math.PI * 2;
  }

  drawScene();

  // FPS更新
  var now = new Date();
  if (lastFtpUpdate.getSeconds() != now.getSeconds()) {
    this.lastFtpUpdate = now;
    document.getElementById('msg').innerText = this.currentFps + " fps";
    this.currentFps = 1;
  } else {
    this.currentFps++;
  }
}

frameファンクションはフレーム毎にオブジェクトのステータスを更新します。たとえば回転させたり色を変更したりするような処理を行います。drawSceneファンクションは画面にオブジェクトを描画処理を行います。

// 描画処理
function drawScene() {

  // 動画呼び出し要請(frameが自動的に再度呼び出される)
  requestAnimationFrame(frame);

  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  // 投影行列初期化
  mat4.perspective(45, canvas.width / canvas.height, 0.1, 10.0, pMatrix);
  mat4.translate(pMatrix, [-0.0, -0.4, 0]);

  // グローバルオブジェクト変換行列初期化
  mat4.identity(mvMatrix);
  mat4.translate(mvMatrix, [0.0, 0.0, -1.6]);
  mat4.rotateY(mvMatrix, angle);

  // Modelオブジェクトを画面に出力
  drawModel(model);
}

プログラムの紹介は以上です。Chrome、最新版Firefox、IE11でcat.htmlファイルを開いて、リアルタイムの3Dグラフィックをお楽しみください。

ダウンロードとサンプル

この文書で利用したファイル一式のダウンロードはこちらです。

Webページでのリアルタイムの3Dグラフィック再生:

run_time

(Chrome、Firefox最新版、IE11以上のブラウザをご利用ください)

Jingwood

北海道の田舎で暮らしているプログラマーです。最近山登りにハマりました。

Leave a Reply

Your email address will not be published. Required fields are marked *