サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

Away3D: 立方体を回してみる

ID: FN1402004 Technique: HTML5 and JavaScript Library: Away3D TypeScript

Away3Dはオープンソースのリアルタイム3Dエンジンです。もともとはFlashプラットフォーム向けに開発されました。そのAway3Dエンジンが、「Away3D TypeScript」としてJavaScriptライブラリへの移植が進んでおり、現在アルファリリースが公開されています。このAway3D TypeScriptを使ったごく簡単なJavaScriptコードで、3次元空間に立方体をつくって回してみましょう。なお、本稿は2013年12月3日のビルドにもとづくきます。その後の2014年5月13日付のライブラリ用いた解説は、同名のノート「Away3D: 立方体を回してみる」をお読みください。


01 Away3D TypeScriptライブラリを使う

Away3D TypeScript」サイトには、作例やソースファイルのリンクなどが掲げられています。最新のライブラリは、「Source Files」の欄に示された「GitHub: Away3D Core TypeScript」のリンクからダウンロードできます(後掲図002上)。ところが、本稿執筆時に筆者が試した2014年1月30日付のJavaScript(JS)ファイル「Away3D.next.min.js」(図001)は、script要素に読込んでも初期化できずエラーが起こってしまいました(「Away3D.next.js」でも同じ)。

図001■2014年1月30日付のAway3D TypeScriptライブラリファイル
図001

そこで本稿では、動作している作例「GitHub: Away3D Examples」のコードに読込まれているJSファイルを使います(図002上)。ダウンロードしたソースの「libs」フォルダにある「Away3D.next.min.js」(図002下)を、これから書くコードのライブラリ用に定めたフォルダ(本稿では「lib」)に配置します。なお、このJSファイルのタイムスタンプは、2013年12月3日です。

図002■作例のソースへのリンクと用いられているJSファイル
図002上

図002下

HTMLドキュメントには、まずscript要素にAway3D.next.min.jsを読込みます。つぎに、JavaScriptコードには初めに呼出す関数(initialize())を設け、body要素のonload属性にその呼出しを加えます。これで準備が整いました。Away3Dのコードを書いていきましょう。

<script src="lib/Away3D.next.min.js"></script>
<script>
function initialize() {
  // 初期設定
}
</script>


<body onload="initialize();">

Away3Dの3次元表現で用意しなければならないのは、つぎの3つです。第1に、舞台となる3次元空間をつくります。第2に、その舞台に照明を備えます。そして第3に、役者となる物体を舞台に登場させます。項を改めて、順にご説明します。

    Away3Dで用意しなければならないもの
  1. 舞台   View3Dオブジェクトで3次元空間の表示領域を定める
  2. 照明   光源のオブジェクトで3次元空間を照らす
  3. 役者   幾何情報と素材からMeshオブジェクトをつくる

02 View3Dクラスで3次元空間の表示領域を定める

第1につくらなければならないのは、3次元空間の表示領域を定めるView3Dオブジェクトです。3次元の座標空間や、それを表示領域に映すカメラもオブジェクトの中にもちます。View3D()コンストラクタは、引数なしに呼出して構いません。

new away.containers.View3D()

View3Dオブジェクトには、プロパティで設定が加えられます(表001)。プロパティの数は多いものの、多くはデフォルト値が定められています。今回は、ごく基本的なプロパティのみ定めることにします。

表001■View3Dクラスに備わる基本的なプロパティ
View3Dクラスの
プロパティ
プロパティの値
width
height
表示される領域の幅と高さ。デフォルト値は640×480ピクセル。
backgroundColor 画面の背景色。デフォルト値は黒(0x000000)。
antiAlias 用いられるアンチエイリアスの大きさ。デフォルト値は0。
camera 表示領域を描くために用いられるCamera3Dオブジェクト。
scene 表示領域を描くもととなる3次元空間のScene3Dオブジェクト。

View3Dオブジェクトをつくって返す関数(createView())は新たに設けます。引数には、表示領域の幅と高さ、背景色、それにアンチエイリアスの大きさを渡します。

createView(幅, 高さ, 背景色, アンチエイリアス)

できあがりのJavaScriptは、後にまとめてコード001として掲げます。関数(createView())は、つぎの抜書きのように定めました(第12〜19行目)。そして、初期設定の関数(initialize())から呼出します(第5行目)。なお、行番号は後掲コード001にもとづきます。

  1. var view;
  2. function initialize() {
  1.   view = createView(240, 180, 0x000000, 4);
  1. }
  2. function createView(width, height, backgroundColor, antiAlias) {
  3.   var view = new away.containers.View3D();
  4.   view.width = width;
  5.   view.height = height;
  6.   view.backgroundColor = backgroundColor;
  7.   view.antiAlias = antiAlias;
  8.   return view;
  9. }

03 DirectionalLightクラスで平行光源を定める

第2に、光源を定めます。3次元空間をつくっても、光がなければ見えません。神と同じく「光りあれ」と、光をつくらなければならないのです。3次元表現で使われる光源はいくつかあります。その中でも基本となるのは「平行光源」(directional light)です。太陽の光のように同じ向き(平行)に進み、距離によって強さが変わりません(図003右上)。

図003■3次元表現で使われる光源の種類
図003
*Tcpp's fileより引用

平行光源は、DirectionalLight()コンストラクタで定めます。引数はなくて構いません。この光で、この後つくる物体の表面を照らします。

new away.lights.DirectionalLight()

もっとも、太陽光だけでは、月のように光の当たっていない部分は暗闇になってしまいます。地球上では「環境光」(ambient light)があることで、陰も見えるのです。DirectionalLightオブジェクトのambientプロパティに強さの数値を与えると、環境光が加わります。そこで、DirectionalLightオブジェクトをつくって返す関数(createDirectionalLight())は、環境光の強さを引数に与えてつぎのように定めます。

createDirectionalLight(環境光の強さ)
  1. function initialize() {
  2.   var directionalLight = createDirectionalLight(0.25);
  1. }
  1. function createDirectionalLight(ambient) {
  2.   var directionalLight = new away.lights.DirectionalLight();
  3.   directionalLight.ambient = ambient;
  4.   return directionalLight;
  5. }

04 Meshクラスで立方体をつくる

ようやく、舞台と照明が整いました。いよいよ第3の、役者となる物体のMeshオブジェクトを登場させます。Mesh()コンストラクタには、幾何情報と表面素材のオブジェクトを引数に渡します。

new away.entities.Mesh(幾何情報, 素材)

立方体の幾何情報は、CubeGeometryオブジェクトで定めます。CubeGeometryI()コンストラクタには、引数として幅と高さおよび奥行きの数値を与えます。

new away.primitives.CubeGeometry(幅, 高さ, 奥行き)

素材としては、表面をひとつの色で塗ることにします。定めるのはColorMaterialクラスで、コンストラクタにはカラー値の整数を渡します。

new away.materials.ColorMaterial(カラー値)

物体の表面を照らす光はStaticLightPickerオブジェクトで定め、素材のオブジェクトのlightPickerプロパティに加えます。StaticLightPicker()コンストラクタには、光源のオブジェクトを配列に納めて渡します。

new away.materials.StaticLightPicker(光源の配列)

これらのオブジェクトから立方体のMeshオブジェクトをつくって返す関数(createCube())はつぎのように定めます。引数には、幅と高さと奥行きに加えて、素材のカラー値および光源のオブジェクトを渡します。

createCube(幅, 高さ, 奥行き, カラー値, 光源)

関数(createCube())は、CubeGeometryとColorMaterialオブジェクトからMeshインスタンスをつくり、光源のオブジェクトを設定して返します(第20〜26行目)。この関数は、初期設定の関数(initialize())から呼出して、できあがったMeshインスタンスを3次元空間に加えます。3次元空間のScene3DオブジェクトはView3D.sceneプロパティで参照し(前掲表001)、Scene3D.addChild()メソッドの引数としてインスタンスを渡します(第7行目)。

そして、3次元空間に手が加わったら、表示領域に描き直すため、必ずView3D.render()を呼出します(第10行目)。これで、画面に立方体が表れます。

  1. var mesh;
  2. var view;
  3. function initialize() {
  4.   var directionalLight = createDirectionalLight(0.25);
  5.   view = createView(240, 180, 0x000000, 4);
  6.   mesh = createCube(400, 400, 400, 0x00FFFF, directionalLight);
  7.   view.scene.addChild(mesh);
  1.   view.render();
  2. }
  1. function createCube(width, height, depth, color, light) {
  2.   var geometry = new away.primitives.CubeGeometry(width, height, depth);
  3.   var material = new away.materials.ColorMaterial(color);
  4.   var mesh = new away.entities.Mesh(geometry, material);
  5.   material.lightPicker = new away.materials.StaticLightPicker([light]);
  6.   return mesh;
  7. }

もっとも、このまま描かれる立方体は真正面向きですので、前面の正方形しか見えません。そこで、x軸とy軸周りに少し角度を傾けます(図004)。Meshオブジェクトのプロパティとして、rotationXrotationYにそれぞれの角度を与えました(第8〜9行目)。これらをまとめたのが、つぎのコード001です。

図004■3次元空間に描かれた立方体
図004

コード001■3次元空間に立方体を描く
  1. var mesh;
  2. var view;
  3. function initialize() {
  4.   var directionalLight = createDirectionalLight(0.25);
  5.   view = createView(240, 180, 0x000000, 4);
  6.   mesh = createCube(400, 400, 400, 0x00FFFF, directionalLight);
  7.   view.scene.addChild(mesh);
  8.   mesh.rotationX = -30;
  9.   mesh.rotationY = 30;
  10.   view.render();
  11. }
  12. function createView(width, height, backgroundColor, antiAlias) {
  13.   var view = new away.containers.View3D();
  14.   view.width = width;
  15.   view.height = height;
  16.   view.backgroundColor = backgroundColor;
  17.   view.antiAlias = antiAlias;
  18.   return view;
  19. }
  20. function createCube(width, height, depth, color, light) {
  21.   var geometry = new away.primitives.CubeGeometry(width, height, depth);
  22.   var material = new away.materials.ColorMaterial(color);
  23.   var mesh = new away.entities.Mesh(geometry, material);
  24.   material.lightPicker = new away.materials.StaticLightPicker([light]);
  25.   return mesh;
  26. }
  27. function createDirectionalLight(ambient) {
  28.   var directionalLight = new away.lights.DirectionalLight();
  29.   directionalLight.ambient = ambient;
  30.   return directionalLight;
  31. }

前掲コード001の動きが確かめられるように、jsdo.itにサンプルコードを掲げました(サンプル001)。

サンプル001■Away3D: Cube in the 3D space


05 立方体を水平および垂直に回す

それでは仕上げとして、3次元空間の立方体を上下左右に回してみましょう。アニメーションは、RequestAnimationFrameクラスで扱います。一定の時間間隔で行うアニメーションの処理を関数で定め、コンストラクタの引数として渡します。コールバック関数が呼出される頻度は、1秒間に約60回です[*1]。なお、コールバックの呼出しは、RequestAnimationFrame.start()メソッドにより始まります。

new away.utils.RequestAnimationFrame(コールバック)

RequestAnimationFrameオブジェクト.start()

上述のふたつのメソッドは、初期設定の関数から呼出します(第8〜9行目)。なお、以下の抜書きの行番号は、後に全体を掲げるコード002にもとづきます。RequestAnimationFrame()コンストラクタに渡したコールバック関数(rotate())は、x軸とy軸周りの角度を1度ずつ加えています(第32〜35行目)[*2]。なお、角度を360度の剰余(%)としているのは、値が果てしなく大きくなることを避けるためです。

  1. function initialize() {
      // mesh.rotationX = -30;
      // mesh.rotationY = 30;

  1.   var animationFrame = new away.utils.RequestAnimationFrame(rotate);
  2.   animationFrame.start();
  1. }
  1. function rotate(timestamp) {
  2.   var rotationX = (mesh.rotationX + 1) % 360;
  3.   var rotationY = (mesh.rotationY + 1) % 360;
  4.   mesh.rotationX = rotationX;
  5.   mesh.rotationY = rotationY;
  6.   view.render()
  7. };

つぎのコード002にJavaScript全体をまとめました。これで、3次元空間の立方体は上下左右に回ります。jsdo.itにも同じサンプルコードを掲げました(サンプル002)。

コード002■3次元空間の立方体をx軸およびy軸で回す
  1. var mesh;
  2. var view;
  3. function initialize() {
  4.   var directionalLight = createDirectionalLight(0.25);
  5.   view = createView(240, 180, 0x000000);
  6.   mesh = createCube(400, 400, 400, 0x00FFFF, directionalLight);
  7.   view.scene.addChild(mesh);
  8.   var animationFrame = new away.utils.RequestAnimationFrame(rotate);
  9.   animationFrame.start();
  10.   view.render();
  11. }
  12. function createView(width, height, backgroundColor) {
  13.   var view = new away.containers.View3D();
  14.   view.width = width;
  15.   view.height = height;
  16.   view.backgroundColor = backgroundColor;
  17.   return view;
  18. }
  19. function createCube(width, height, depth, color, light) {
  20.   var geometry = new away.primitives.CubeGeometry(width, height, depth);
  21.   var material = new away.materials.ColorMaterial(color);
  22.   var mesh = new away.entities.Mesh(geometry, material);
  23.   material.lightPicker = new away.materials.StaticLightPicker([light]);
  24.   return mesh;
  25. }
  26. function createDirectionalLight(ambient) {
  27.   var directionalLight = new away.lights.DirectionalLight();
  28.   directionalLight.ambient = ambient;
  29.   return directionalLight;
  30. }
  31. function rotate(timestamp) {
  32.   var rotationX = (mesh.rotationX + 1) % 360;
  33.   var rotationY = (mesh.rotationY + 1) % 360;
  34.   mesh.rotationX = rotationX;
  35.   mesh.rotationY = rotationY;
  36.   view.render();
  37. }

サンプル002■Away3D: Rotating a cube in the 3D space

[*1] RequestAnimationFrameオブジェクトは、内部的にwindow.requestAnimationFrame()メソッドを使っています。window.requestAnimationFrame()は、ブラウザが画面を描画し直そうとするとき、コールバック関数を呼出すメソッドです。再描画は画面のリフレッシュレートにもとづきますので、呼出しの頻度は一般的な60Hzでは1秒間に60回ほどです。

[*2] x軸とy軸だけで、z軸は使わなくても、上下左右の回転はできます。z軸による回転は、xy平面で回すことを意味します。同じように、x軸ならyz平面上の回転になります。yz平面はy軸で90度回せば、xy平面に重なります。つまり、x軸とy軸で、z軸と同じ回転が表せるのです。


05 Away3Dをさらに試してみる

Away3Dをさらに試してみたいという方は、現在ICS LABで「簡単なJSで始めるWebGL対応Away3Dチュートリアル」という連載が始まっています。本稿執筆時では、つぎの3回分が公開されていますので、読まれるとよいでしょう。



作成者: 野中文雄
更新日: 2014年5月22日 2014年5月13日付ビルドにもとづく解説へのリンクを追加。
作成日: 2014年2月17日


Copyright © 2001-2014 Fumio Nonaka.  All rights reserved.