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ライブラリファイル
そこで本稿では、動作している作例「GitHub: Away3D Examples」のコードに読込まれているJSファイルを使います(図002上)。ダウンロードしたソースの「libs」フォルダにある「Away3D.next.min.js」(図002下)を、これから書くコードのライブラリ用に定めたフォルダ(本稿では「lib」)に配置します。なお、このJSファイルのタイムスタンプは、2013年12月3日です。
図002■作例のソースへのリンクと用いられているJSファイル
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で用意しなければならないもの
- 舞台 View3Dオブジェクトで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にもとづきます。
- var view;
- function initialize() {
- view = createView(240, 180, 0x000000, 4);
- }
- function createView(width, height, backgroundColor, antiAlias) {
- var view = new away.containers.View3D();
- view.width = width;
- view.height = height;
- view.backgroundColor = backgroundColor;
- view.antiAlias = antiAlias;
- return view;
- }
|
03 DirectionalLightクラスで平行光源を定める
第2に、光源を定めます。3次元空間をつくっても、光がなければ見えません。神と同じく「光りあれ」と、光をつくらなければならないのです。3次元表現で使われる光源はいくつかあります。その中でも基本となるのは「平行光源」(directional light)です。太陽の光のように同じ向き(平行)に進み、距離によって強さが変わりません(図003右上)。
図003■3次元表現で使われる光源の種類
*Tcpp's fileより引用
平行光源は、DirectionalLight()コンストラクタで定めます。引数はなくて構いません。この光で、この後つくる物体の表面を照らします。
new away.lights.DirectionalLight()
もっとも、太陽光だけでは、月のように光の当たっていない部分は暗闇になってしまいます。地球上では「環境光」(ambient light)があることで、陰も見えるのです。DirectionalLightオブジェクトのambientプロパティに強さの数値を与えると、環境光が加わります。そこで、DirectionalLightオブジェクトをつくって返す関数(createDirectionalLight())は、環境光の強さを引数に与えてつぎのように定めます。
createDirectionalLight(環境光の強さ)
- function initialize() {
- var directionalLight = createDirectionalLight(0.25);
- }
- function createDirectionalLight(ambient) {
- var directionalLight = new away.lights.DirectionalLight();
- directionalLight.ambient = ambient;
- return directionalLight;
- }
|
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行目)。これで、画面に立方体が表れます。
- var mesh;
- var view;
- function initialize() {
- var directionalLight = createDirectionalLight(0.25);
- view = createView(240, 180, 0x000000, 4);
- mesh = createCube(400, 400, 400, 0x00FFFF, directionalLight);
- view.scene.addChild(mesh);
- view.render();
- }
- function createCube(width, height, depth, color, light) {
- var geometry = new away.primitives.CubeGeometry(width, height, depth);
- var material = new away.materials.ColorMaterial(color);
- var mesh = new away.entities.Mesh(geometry, material);
- material.lightPicker = new away.materials.StaticLightPicker([light]);
- return mesh;
- }
|
もっとも、このまま描かれる立方体は真正面向きですので、前面の正方形しか見えません。そこで、x軸とy軸周りに少し角度を傾けます(図004)。Meshオブジェクトのプロパティとして、rotationXとrotationYにそれぞれの角度を与えました(第8〜9行目)。これらをまとめたのが、つぎのコード001です。
図004■3次元空間に描かれた立方体
コード001■3次元空間に立方体を描く
- var mesh;
- var view;
- function initialize() {
- var directionalLight = createDirectionalLight(0.25);
- view = createView(240, 180, 0x000000, 4);
- mesh = createCube(400, 400, 400, 0x00FFFF, directionalLight);
- view.scene.addChild(mesh);
- mesh.rotationX = -30;
- mesh.rotationY = 30;
- view.render();
- }
- function createView(width, height, backgroundColor, antiAlias) {
- var view = new away.containers.View3D();
- view.width = width;
- view.height = height;
- view.backgroundColor = backgroundColor;
- view.antiAlias = antiAlias;
- return view;
- }
- function createCube(width, height, depth, color, light) {
- var geometry = new away.primitives.CubeGeometry(width, height, depth);
- var material = new away.materials.ColorMaterial(color);
- var mesh = new away.entities.Mesh(geometry, material);
- material.lightPicker = new away.materials.StaticLightPicker([light]);
- return mesh;
- }
- function createDirectionalLight(ambient) {
- var directionalLight = new away.lights.DirectionalLight();
- directionalLight.ambient = ambient;
- return directionalLight;
- }
|
前掲コード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度の剰余(%)としているのは、値が果てしなく大きくなることを避けるためです。
- function initialize() {
// mesh.rotationX = -30;
// mesh.rotationY = 30;
- var animationFrame = new away.utils.RequestAnimationFrame(rotate);
- animationFrame.start();
- }
- function rotate(timestamp) {
- var rotationX = (mesh.rotationX + 1) % 360;
- var rotationY = (mesh.rotationY + 1) % 360;
- mesh.rotationX = rotationX;
- mesh.rotationY = rotationY;
- view.render()
- };
|
つぎのコード002にJavaScript全体をまとめました。これで、3次元空間の立方体は上下左右に回ります。jsdo.itにも同じサンプルコードを掲げました(サンプル002)。
コード002■3次元空間の立方体をx軸およびy軸で回す
- var mesh;
- var view;
- function initialize() {
- var directionalLight = createDirectionalLight(0.25);
- view = createView(240, 180, 0x000000);
- mesh = createCube(400, 400, 400, 0x00FFFF, directionalLight);
- view.scene.addChild(mesh);
- var animationFrame = new away.utils.RequestAnimationFrame(rotate);
- animationFrame.start();
- view.render();
- }
- function createView(width, height, backgroundColor) {
- var view = new away.containers.View3D();
- view.width = width;
- view.height = height;
- view.backgroundColor = backgroundColor;
- return view;
- }
- function createCube(width, height, depth, color, light) {
- var geometry = new away.primitives.CubeGeometry(width, height, depth);
- var material = new away.materials.ColorMaterial(color);
- var mesh = new away.entities.Mesh(geometry, material);
- material.lightPicker = new away.materials.StaticLightPicker([light]);
- return mesh;
- }
- function createDirectionalLight(ambient) {
- var directionalLight = new away.lights.DirectionalLight();
- directionalLight.ambient = ambient;
- return directionalLight;
- }
- function rotate(timestamp) {
- var rotationX = (mesh.rotationX + 1) % 360;
- var rotationY = (mesh.rotationY + 1) % 360;
- mesh.rotationX = rotationX;
- mesh.rotationY = rotationY;
- view.render();
- }
|
サンプル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日