LuaJITでお手軽3Dプログラミング (5) (2014/03/31, 2017/12/24)
LjES ver.2.01 について
「LuaJITでお手軽3Dプログラミング (1)、(2)、(3)、(4)」で使っている Raspberry Pi 専用の3DライブラリLjES ですが、機能を追加して LjES ver.2.01 として公開します。前バージョン(ljes-1.00)では、球とか立方体といった形状以外は扱いにくかったので、Blender で作成して Collada 形式でエクスポートした3Dモデルを読み込む機能を追加しました。また、3Dモデルの内部に骨(ボーン)を埋め込んで変形する機能 (Skeletal Animation、Bone Animation) もサポートしました。これまでの「LuaJITでお手軽3Dプログラミング (1)、(2)、(3)、(4)」のサンプルは修正の必要はありません。
LjES ver.2.00 は Raspbian Jessie以前用です
Blender(ブレンダー)は、3次元コンピュータグラフィックスを作成する非常に高機能のソフトウェアで、モデリング(3Dモデルの作成)、レンダリング(画像の生成)、アニメーション、ゲームエンジンとしての機能も備える無料(オープンソース)で使用できます。サポートされているプラットフォームは Windows、Linux, MacOSX などでほとんどのコンピュータで使用できます。
LjESは、LuaJIT という非常に高速なスクリプト言語を使って、 3Dアニメーションのプログラミング経験がなくても3Dプログラミングを手軽に楽しめることを目的としています。 Raspberry Pi の公式ディスクイメージの Raspbian には最初から LuaJIT が入っているため、新たに何もインストールする必要もなくプログラミングを始められます。 サンプルプログラムを試すには LjESを解凍したディレクトリでデモのスクリプトを実行するだけです。
hand.lua
demo_spheres.lua
LjES のダウンロードと使い方
LjES はいくつかの画像ファイルとテキストだけが含まれています。テキストの多くはLua言語のソースプログラムで、Raspberry Piでそのまま実行できます。
ljes-2.01.tar.gz (514KB)
GitHub (https://github.com/jun-mizutani/ljes.git )
適当なディレクトリで次のコマンドを実行すると、LjESのダウンロードと展開、デモの実行まで行います。
curl -O https://www.mztn.org/rpi/ljes-2.01.tar.gz tar zxf ljes-2.01.tar.gz cd ljes-2.01 cd examples luajit hand.lua
examples ディレクトリのサンプルは [q] キーを押すか、2分程経過すると終了します。キーを押した場合の動作を下に示します。
キー | 動作 |
---|---|
h | ヘルプ |
q | 終了 |
w | ノードの回転 +X |
s | ノードの回転 -X |
a | ノードの回転 +Y |
d | ノードの回転 -Y |
z | ノードの回転 +Z |
x | ノードの回転 -Z |
e | ボーンの回転 +X |
r | ボーンの回転 -X |
y | ボーンの回転 +Y |
u | ボーンの回転 -Y |
c | ボーンの回転 +Z |
v | ボーンの回転 -Z |
o | メッシュを隠す |
i | メッシュを表示 |
m | メッシュの選択 (+1) |
n | メッシュの選択 (-1) |
j | ボーンの選択 (+1) |
k | ボーンの選択 (-1) |
@ | アニメーションの再生 |
1 | 指で 1 を示す |
2 | 指で 2 を示す |
3 | 指で 3 を示す |
4 | 指で 4 を示す |
5 | 手を開く |
6 | 手を握る |
9 | ボーンを表示する |
0 | ボーンを隠す |
p | スクリーンショットを PNG で取得 |
t | 描画領域を右上に |
b | 描画領域を右下に |
g | 描画領域のサイズを戻す |
f | フルスクリーン |
LjES-2.01 の構成
LjES は大体下の図に示すような構成になっています。 図の青い部分の demo.lua はLjESの全体を使うための簡単なフレームワークになっています。グリーンの部分のbcm.lua、egl.lua、 png.lua、 gles.lua、 termios.lua は、どんな Linux のディストリビューションでも持っているシステム用の共有ライブラリ(図中の赤い部分)を LuaJIT から使うための低レベルなコードです。残りの黄色の部分は LjES のクラスライブラリ群です。 OpenGL ES2で必要となる行列演算、GPUへの転送、シェーダプログラミングといった機能や物体の形状や動作の指定、画面への文字表示といった部分を担当しています。ライトブルーのモジュールは COLLADA ファイルの読み込みとアニメーションを担当します。
クラスモジュールの依存関係とクラスの継承による階層構造です。
Colladaのアニメーションサンプル
次のコードは LjES-2 を使ってCollada形式のアニメーションを表示します。 Collada 形式は非常に自由度が高いため、LjES-2 では Blenderから Collada 形式でエクスポートしたファイルのみを対象としています。Blender 上でのメッシュは LjES の Shape に変換され、1つの Shape は最大40本のボーンを埋め込むことができます。Blender 上でメッシュとボーン(Armature)の原点(0, 0, 0)は一致させる必要があります。Rest Positionでエクスポートして下さい。
package.path = "../LjES/?.lua;" .. package.path local demo = require("demo") require("ColladaShape") if arg[1] ~= nil then collada_file = arg[1] else print("usage: luajit dae_anim0.lua your_collada.dae") return end demo.screen(0, 0) local aSpace = demo.getSpace() demo.backgroundColor(0.2, 0.2, 0.4) -- load collada local collada = ColladaShape:new() local collada_text = util.readFile(collada_file) collada:parse(collada_text ,true) local shapes = collada:makeShapes(true, true) -- set object local node = aSpace:addNode(nil, "node") for i = 1, #shapes do shapes[i]:shaderParameter("color", {0.8, 0.7, 0.6, 1.0}) node:addShape(shapes[i]) end -- set eye position local eye = aSpace:addNode(nil, "eye") local size = demo.getShapeSize(shapes) eye:setPosition(size.centerx, size.centery, size.max*2) -- setup animation node.shapes[1].anim:start() -- call back function function draw() demo.aText:writeAt(2, 24, "[q] : quit") node.shapes[1].anim:play() -- play one frame of animation aSpace:draw(eye) end -- main loop demo.loop(draw, true) demo.exit()
Shape
回転するドーナッツを表示するアプリケーションは次に示すように 20行ほどのコードで作成することができます。 コードの赤い部分を変更すると、物体の形状や動きを変更することができます。 前バージョン(ljes-1.00)からの変更はありません。
package.path = "../LjES/?.lua;" .. package.path local demo = require("demo") demo.screen(0, 0) local aSpace = demo.getSpace() local eye = aSpace:addNode(nil, "eye") eye:setPosition(0, 0, 30) demo.backgroundColor(0.2, 0.2, 0.4) local shape = Shape:new() shape:donut(8, 3, 16, 16) shape:endShape() shape:shaderParameter("color", {0.5, 0.3, 0.0, 1.0}) local node = aSpace:addNode(nil, "node1") node:setPosition(0, 0, 0) node:addShape(shape) function draw() node:rotateX(0.1) aSpace:draw(eye) end demo.loop(draw, true) demo.exit()
この例は、[q] キーを押すか、14 分ほど経過すると終了します。 [p] キーを押すとカレントディレクトリに "ss_date_time.png" というファイル名でスクリーンショットを保存します。
コードの詳細は こちらを参照して下さい。