タグ別アーカイブ: ソフト開発

プログラミングやソフト開発に関する話題。

てすt

最近は2Dの衝突判定処理を自作しようとしているのだが、前にObjective-Cで衝突判定処理を作ったときの反省を生かして、今回はデバッグやテストを十分に行うことにした。で、恥ずかしながら今さら、JUnitを本格的に使うことにした。

今までJUnit系はActionScriptで使ったことがあるが、なんかその時の面倒さから敬遠してて、Javaのウニットテストはmain関数にassertをばらまいたようなことをやっていた。今回はちゃんとやるぜ!

で、そのJUnit。NetBeansが母体となっているjME(jMonkeyEngine) SDKにインストールしてみたはいいんだが、動かねーぞ。原因は分かった。 テストケースのクラス名をHogeTestみたいに、最後をTestとつけなければNetBeansが認識しないらしい。それはnbprojectディレクトリに含まれる、build-impl.xmlに記述されている”**/**Test”と指定されているのが原因だと、どっかのWEBで言ってた。build-impl.xmlには手をつけたくない(というか手をつけてはいけない?)ので、黙ってその末尾Testルールに従う。

あと、今回はテストで画像ファイル(SVGファイル)を吐き出したいと思っている。その吐き出し先のディレクトリを指定したいのだが、普通のアプリの場合はmainの引数にコマンドラインオプションとして指定していた。が、テストケースの場合はその指定の仕方がいまいち良く分からない。面倒くさいからコマンドラインオプションはやめて、環境変数で指定することにした。

それをやるには System.getenv( str ) で出来る。簡単だね!

System.getProperty( str ) は似たようなやり方だが、Java VMのオプション -Dで追加しないといけないぞう。

マウスでグリグリ

3DCGArtsでポリゴンオブジェクトをグリグリ回転するような操作をトラックボール操作というらしい。なるほどねー、言われてみれば確かにトラックボールだ。

今回はそれをjME(jMonkeyEngine)で実装してみた。

最初は3Dの一般的なところから検索してみて、見つかったのがここのやり方。
http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20040321

ここに載っているアルゴリズムのように実装してみたのだが、どうもあまりうまく動いてくれない。たぶん、自分のプログラムはSpatialオブジェクトのWorldTransformではなく、LocalTransformを操作しているのが間違いなんだと思う。しかし、WorldTransformを直接変更する方法はなく、間接的に変更する方法も調べたが結局分からなかった。

あきらめてjMEの公式サイトを漁ってみたら、そのものズバリがソース付きで載っていた。http://hub.jmonkeyengine.org/forum/topic/trackball-samples/

にゃるほどお~、lookAt関数を使うのか。lookAt関数って中身のソースを見てみたけど、全然よく分からないのよね。というかlookAt関数の元となる考え方Quanternion(四元数)自体がよくわからん。近所の本屋に扱っている本がなかったし、近所の図書館にもなかった。(中央図書館にはあるみたいだけど)

3Dではバリバリ使われているの考え方なのに、一般ではあまり需要がないのかな?まー、いずれは本腰をあげて身につけたい分野ではある。

で、今回、実装したのはこんな感じだ!

マウスモーションのイベントハンドラで、lookAtとlookUpはVector3fのメンバ変数。対象のspatialのlookAt関数の引数に使用される。sign関数は単純なもので、引数が負であれば-1、正であれば+1、ゼロであれば0を返す。sign関数を使った処理でマウスをクリックしたまま方向転換した時に変な動きにならないように補正してある。

if( mousePressed ){
int x_ = ev_.getX();
int y_ = ev_.getY();
int dx_ = mouseX0 – x_;
int dy_ = mouseY0 – y_;
float sx_ = -(float)dx_/(float)screenWidth;
float sy_ = (float)dy_/(float)screenHeight;
{
int sign0_ = sign( lastX – mouseX0 );
int sign1_ = sign( x_ – lastX );
if( sign0_ != 0 && sign1_ != sign0_ ){
mouseX0 = lastX = x_;
}
lastX = x_;
}
{
int sign0_ = sign( lastY – mouseY0 );
int sign1_ = sign( y_ – lastY );
if( sign0_ != 0 && sign1_ != sign0_ ){
mouseY0 = lastY = y_;
}
lastY = y_;
}
++debugCount;
Quaternion xq_ = new Quaternion().fromAngleAxis(
FastMath.QUARTER_PI*sx_, Vector3f.UNIT_Y
);
Quaternion yq_ = new Quaternion().fromAngleAxis(
FastMath.QUARTER_PI*sy_, Vector3f.UNIT_X
);
xq_.multLocal( lookAt );
xq_.multLocal( lookUp );
yq_.multLocal( lookAt );
yq_.multLocal( lookUp );
}

Java Web ☆★☆★☆★t!

スタートしちゃうぞーーーー!
やっと、Java Web Startで3DアプリがDeployできた。
↓ここをクリックすると起動できる。

http://kekkouyakan.webcrow.jp/jmeapp/viewer20130722.jnlp

アプレットに比べて簡単だった。もうアプレットなんかやんねーーー!!
まだこのアプリ自体は完成度が低く、ESCキーを押すとフリーズするので注意!

次はこのアプリの完成度をもうちょっとあげて、公開しよう。
この変更で、JNLPファイルの内容を確認できれば、特にここで記すことは何も無い。

アプレットができねえ

とりあえず、Swingで作ったJME (jMonkeyEngine)のアプリだが、アニメーションまで実装できて順調だったが、アプレットで頓挫した。JApplet拡張クラスさえ作れば後は余裕のよっちゃんだと思ってたんだけどなあ。

まず、Ubuntu限定かは知らないけど、LinuxではJDK(JRE)をインストールしてても、アプレットが正常に動作しない。Javaプラグインに問題があるようだ。なんかWebを色々検索して模索してたらいつの間にか直ってた。どういう対策したかは忘れてしまったので省略。もともとインストールしてたOpenJDKじゃなくて、OracleJDKをインストールしたのが良かったのかもしれない。(OpenJDKってバグがけっこう目について、あまり信用できないんだよねえ。)
といっても、対策してもFirefoxでしかアプレットが動作しなくて、Operaでは結局動作できてない。

次に、アプレットをアップロードする先のサーバの選定にも苦労した。当初はFC2でやろうと思っていたが、ftpにログインできねー。なんかよくわからん。FC2以外で他に2、3個試したが、アップロードしても全く表示されなかったりなかなか思うようなサーバがみつからなかった。学生時代はジオシティーズで気軽に出来たけど、まー、あれはちょっとヤボな事情があって却下。結局、webcrowというところで今は落ち着いている。
http://www.webcrow.jp

最後に、今回解決できなかったのがアプレットのセキュリティ制約だ。なんかjarsignerというツールを使ってjarファイルにオレオレ署名とかはいいんだが、それでもセキュリティ制約でエラーが起きる。アプレットだからローカルファイルにアクセスしないように配慮して作ったのだが、OpenGLという技術でGPUにアクセスするようなアプリのためなのか、原因不明のセキュリティエラーが出る。

JMEはLWJGLというOpenGLライブラリをベースにしており、そこによれば、Applet Loaderというユーティリティを使えと書いてはあるのだが、、。
http://www.ninjacave.com/appletloader
ちなみに、某所で有名なゲーム「Minecraft」もこのLWJGLを使っているようで、検索してるとMinecraftのページがよくヒットしてた。

そのApplet Loaderを使っても相変わらずエラーが出る。しかもappletviewerのローカルで出てくるエラーと、サーバ上に置いてあるアプレットのオンラインなエラーもなんか種類が違っていて、もうお手上げ状態。
泣きそうなので、アプレットはちょっとあきらめようと思う。

代わりに、次はJava Web Startとかいうのを試してみる。この技術はなんかコッソリとPCにプログラムをインストールされている感じがあってあまり好きじゃなかったりするのだが、ブラウザから一回のクリックで即起動するというのはやはり魅力的だ。

ウォラッシヤアアアラアアアアアッ(Swingの巻)

室伏参考URL
http://museru.digi2.jp/g03/g03.html (まんなか辺り)

JME(jMonkeyEngine) SDKのデキがイマイチだ、、。CustomControl系を編集すると、SDKがバグって深刻な編集不能状態に陥ることが多々あり、ちょっと迂闊にSDKでCustomControlに手を出すことが出来ない。あと、衝突判定の設定等ももう少し視覚的、直感的にできるかと思っていたが、なんか無理そうね。

かといって、JMEのライブラリの方はイイデキだし、他に代替もないので、SDKを棄てる訳にもいかない。SDKのバグ修正や機能追加は気が重いので、その穴を埋めるツールを自分で作るしかないなと思った。

そこで欠かせないのがJavaの標準GUIプラットフォームであるSwing。公式ページでもこちらでSwing実装の方法が記されている。
http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:swing_canvas

これに従って実装したのがこちらのソースです。

これで、デフォルトの画面をSwingキャンバスで表示することが出来た。いつもの画面解像度を聞いてくるダイアログボックスも出てこないのでサクサクでいいね。

とりあえず、これをさらに改造して、今までBlenderで作ったモデルを表示し、アニメーションさせ、Appletにするのが、次の目標。

J3OとXMLExporter/Imporer

ひさびさの更新。

3DCGArtsというCG投稿サイトで7/28に開催される獣人祭の出品作品作ってました。
http://www.3dcg-arts.net/member/5289

これが終わると、JME(jMonkeyEngine)のSDKのドキュメントや動画を観てSDKに付属するツール、SceneExplorerやTerrainEditorをいじったりしてた。

で、このSDKの一部であるSceneExplorerなどでは、J3Oファイル(Blenderから出力し、最終的にはJMEに最適化されたファイル)を視覚的に直感的に編集することが出来るのだが、これらはすべてマニュアル操作で行うものだ。

マニュアル操作は再編集が非常に手間がかかる。例えば、編集中のJ3Oファイルの元となったBlenderファイルをBlenderで再編集した場合、その変更点を反映するためにJ3Oファイルに変換すると、マニュアル編集したデータはすべて消えてしまうので、再び同じマニュアル編集を行わなければならない。

マニュアル編集は最初の一度ならいいが、何度も繰り返すとめんどくさいし、間違いなどが紛れ込む恐れもある。だから、これらを防ぐために自動処理でできることはなるべく自動処理に任せるような仕組みを作る必要がある。

これらを実現する第一歩として、以前、BlenderファイルからOgreXMLに変換、OgreXMLからJ3Oファイルに変換する処理を自動化する仕組みを作った。

今回はそれをさらに進めて、J3OファイルをXMLへ出力、逆にXMLからJ3Oファイルに変換する処理を実装した。ソースコードはこちら。以前のOgreXMLからJ3Oへ変換する処理とマージしている。これらの処理はJME APIの提供するXMLExporterとXMLImporterがあれば苦無く実装できる。

で、今回の新機能が実際に役に立つかはまだよく分からない。今回作ったツールを利用して、マニュアル操作する前と後のJ3Oファイルからパッチファイルを作り、そのパッチが正確に反映するような仕組みを今考えているところだ。

以前、XQueryUpdateというXML技術のアプリ、xqillaをインストールしたのだが、あれが使えるといいのだが。
http://xqilla.sourceforge.net/HomePage

ちなみに、JME SDKの右クリックメニューにTools > Diff patchみたいな項目があるが、ここでいうパッチというのは完全にdiffツールのパッチ機能だ。テキストファイルしか扱えないのでバイナリファイルのJ3Oファイルは対象外である。もともとdiffのパッチ機能ってその仕組みからしてちょっと懐疑的なのであまり使う気は無いのだけど。

 

今日は法線を設定しちゃうぞ

Blenderで編集しているときはきれいに表示されてるのに、JME(jMonkeyEngine)では上手く表示できない。。。そういうのが一番困るわー。そして、起きてしまった、そんな事態。次の絵を見てください。

Screenshot from 2013-06-13 21^%14^%35

これはJMEで表示した、JME用に作り直している剣士である。左目とゴーグルが所々欠けてしまっている。Blenderではちゃんと表示されているのに。まえまえから、D君の頃から、BlenderとJMEに表示の違いがあるのを認識しつつ黙殺して進めてきたが、さすがにコレはありえない。覚悟を決めてこの問題を解決すべく、調査や試行錯誤してみた。

で、結論が「法線(Normals)を調整すること」だ!
まあ、前から法線ってうすうす聞いたことありました。例えば球やなめらかな曲面などをそれらしく見せるのに必要なパラメータのようです。ポリゴンは本来、点と点を結ぶ直線の集合でカクカクしたものだけど、法線というもう一つのパラメータを持たせることで線に膨らみを持たせることが出来る。って感じです。あまり詳しいことは分からんけど。

Blenderで法線を表示して確認するにはメッシュをEditModeにして、3DViewの右端に出るメニュー(Nキーで出る)にNormalsという項目があるので、そこにあるボタンをポチポチして好きなように表示することが出来る。

それで確認すると、なるほどー、左目の法線は右目の法線に比べてずっと短くなってたし、ゴーグルの法線も短かった。

これらの法線の長さを調整するにはWキーを押して出てくるメニューの「Flip Normals」でできる。こうして修正して、再度JMEで表示したのがこれ。

Screenshot from 2013-06-13 21^%55^%35

うーん、Good!
なんか、法線問題って3D初心者がよく巡り合う問題のようですな。

JMEにおけるBlenderの制限#3.1

前回の補足。JME(jMonkeyEngine)のAPIドキュメントを読んでいたら、Bone#addChildはユーザコードで使っていけないと書いてあった。代案を探したら、以下のトピックにまんま、おいしいコードがのっかっていた。

Topic : Giving the player a weapon

どうも、読み込んだオブジェクトからSkeletonControlというコントロールにアクセスしてそれで設定できるらしい。これを利用して前回のコードを修正した。(全体はこちら)

52: node_ = assetManager.loadModel(“dist/Models/D08_20130527.mesh.j3o”);
53: AnimControl ctrl_ = node_.getControl(AnimControl.class);
54: AnimChannel ch_ = ctrl_.createChannel();
55: rootNode.attachChild(node_);
56:
57: SkeletonControl sc_ = node_.getControl( SkeletonControl.class );
58: Node node1_ = (Node)assetManager.loadModel(“dist/Models/D08_Excalibur20130527.mesh.j3o”);
59: Node node2_ = sc_.getAttachmentsNode( “hand.equip.R” );
60: node2_.attachChild( node1_ );

これで一応、上手く動く。前回と少し違って、エクスカリバーの”main”というボーンにアクセスしていない。ためしにエクスカリバーのほうもSkeletonControlコントロールを介して”main”のボーンノードを抽出し、D君の”hand.equip.R”というボーンノードにattachChildしてみたが、エクスカリバーがD君の中心位置に表示されてしまい、上手く動かなかった。

上手く動く今回のコードがたぶん正解なのだろう。まだ理屈がよく呑み込めてないけど。

JMEにおけるBlenderの制限#3

ということで、ヨガファイアさん問題が落着したところで残りの懸案を片付ける。

まずは、Blenderで作ったShapeKey/DriversのアニメーションがJME(jMonkeyEngine)で動くかという確認。
けつろん。。。できませんでした!!!

いや、、おそらく出来ないだろうなーと思ってましたのよ。JMEのドキュメントを読んでもメッシュのアニメーションは不可で、ボーンのアニメーションのみサポートって書いてあったし。でもShapeKeyとは直接書いてなかったし、ShapeKeyのアニメーションでもボーンを使うといえば使うし、すこしは望みを残していたのですが、、。やっぱりだめでした!!!

ShapeKeyのアニメーションって便利で、Blenderでも最後の手段だと思ってたので、ぜひサポートして欲しい。どっかのトピックで開発者が熱意を持ってサポートしたいみたいに書いてたのをどこかで読んだ覚えがあるけど。

ShapeKeyはあきらめて次はBlenderのChildOf拘束をJMEでどう実現するかの検討。簡単に言えばChildOf拘束とは2つのボーン同士を親子関係に設定するというもの。前にBlenderで剣士を作ったとき、キャラクターに剣オブジェクトを持たせるのにこのChildOf拘束を利用した。(ここの動画が参考になった。)

JMEではBoneというクラスにaddChildというメソッドがあるので、Blenderで手のボーンに装備スロット的なボーンを追加し、そこに剣のボーンをJMEでaddChildすればよい。実際のコードはこんなかんじになった。

126: Spatial node_ = assetManager.loadModel(“dist/Models/D08_20130527.mesh.j3o”);
127: rootNode.attachChild(node_);
128: AnimControl ctrl_ = node_.getControl(AnimControl.class);
129: AnimChannel ch_ = ctrl_.createChannel();
130: Bone bone_ = ctrl_.getSkeleton().getBone( “hand.equip.R” );
131:
132: Spatial node1_ = assetManager.loadModel(“dist/Models/D08_Excalibur20130527.mesh.j3o”);
133: rootNode.attachChild(node1_);
134: AnimControl ctrl1_ = node1_.getControl(AnimControl.class);
135: Bone bone1_ = ctrl1_.getSkeleton().getBone( “main” );
136:
137: bone_.addChild( bone1_ );

(訂正:APIドキュメントを読み直したら、ユーザコードからBone#addChildは使うなと書いてあった。修正版はこちら)

126行目でD君のオブジェクト、132行目で聖剣エクスカリバーのオブジェクトを読み出し、AnimControlを介してボーンにアクセス、137行目で親子関係を作っている。
ちょっと怪しい動きをしているが、ひとまず期待する実行結果が得られた。

Screenshot from 2013-06-10 00^%35^%03

手抜きレンガ棒(?)じゃないよ!エクスカリバーだよ!

ちなみにBlenderで聖剣エクスカリバーを作っているときに気づいたこと。このエクスカリバーに埋め込んでいるボーンの数は一個のみである。メッシュとボーンを紐付けするときに<Ctrl-P>を押して出てくるメニューに”Armature Deform”と”Bone”という選択肢が出てくるが、”Armature Deform”の方を選択すること。”Bone”を選ぶとBlenderでは問題なく動作するが、JMEではスケルトン情報を取得できず、AnimControlのヌルポが発生する。(Ogreにエクスポートする時点で.skeleton.xmlが出力されない。)

あと、実際に作ったモデルをJMEのみで使う目的ならば、BlenderでChildOf拘束を設定しておく必要はない。でもChildOf拘束を設定しておけばポーズやアニメーションで実際の位置を確認できるので便利である。剣オブジェクトをモデリング時の初期位置に戻したければChildOf拘束のinfluenceを0に設定すればよい。

JMEにおけるBlenderの制限#2

引き続き、キャラクターの腕の太さと長さを設定できるボーン構成をJME(jMonkeyEngine)で実現する課題。(ヨガファイアさん問題と勝手に命名した)

結論から言って、Blenderで設定するStretchTo拘束が犯人だった。この拘束のあるボーンにはメッシュのウェイトを割り振っていなかったので、とくにメッシュに影響が出ると思っていなかったのだが、y軸方向のみのスケール変更をしているせいか、あちこちのボーンに影響が出て、結果、メッシュがおかしな動きをしているようだった。

まとめると、
– 腕の太さの設定はボーンの移動で行うこと。
– IKの影響下にあるボーンのスケール変更は正常に動作する。
– StretchTo拘束は使用しないこと。
となる。

この方針に従い、以下の絵のようにボーンを組んだ。Screenshot from 2013-06-08 23^%09^%51

黄色になっている細長い前腕ボーンにIKが設定されており、細長い無色の上腕ボーンがIKの影響を受ける。IKのアーム操作をしたいときは水色に選択されているボーンを動かす。

この前腕ボーン、上腕ボーンにはそれぞれ十字型に並べられた緑色のボーン4つが付属する。この十字のボーンにメッシュのウェイトが設定されており、これを動かすことで腕の太さを変えることが出来る。

前腕ボーン、上腕ボーン自体にはメッシュのウェイトが設定されていないが、ボーンをスケール変更することで親子関係にある十字ボーンが連動するので、メッシュの腕の長さを変えることが出来る。十字ボーンの数や位置は適当だが、少なくとも肘関節辺りに一つは置いておかないと、ちょっと変な動きになる。

以上、けっこう悩んだ割に、出来上がりはごくシンプルなボーン構成となった。

今回の結論に至る実験で使われたファイルはこちらにアップロードされている。
メモ書き的に各blendファイルの特徴をまとめてみた。

d01_20130527.blend、d02_20130527.blend、d03_20130527.blend
基本的な機能を確認したファイル。これでJMEのスケール変更に関する問題が見つかった。

d04_20130527.blend
ボーンの移動でスケール変更するようにしたもの。上手く動かなかった。

d05_20130527.blend
d04_20130527.blendをベースに、IK拘束とStretchTo拘束を削除したもの。狙った動きになったはなったが、IKを削除したことで、少々操作しにくくなっている。

d06_20130527.blend
d04_20130527.blendをベースに、StretchTo拘束のみを削除したもの。狙った動きになり、IK操作で操作しやすい。