radium.png
HOME | ARCHIVE | PRODUCTS | ABOUT | RSS

8月スタート

2001-08-01

今日から8月。ふと,日記整形スクリプトに過去ログ化機能を付けてないことに気づく。あー,つくらんと。


スクリプトのよもやま話のつづき。

第3の動機は,実行系への依存度を低くするという目的。これは第1,第2の動機とはちがって,プログラマ側の欲求からスクリプト言語が必要になるってケースだ。

僕がいま,ゲームに利用したいとおもっていながらも,もろもろの理由で利用できずにいるものに,マルチスレッドとダイナミックリンクってのがある。WindowsやLinuxみたいな「高等な」OSでは,これらの機能はあたりまえのように備えられていて,みんなあたりまえのように使っているんだけど,一歩外の世界に踏み出すと話がだいぶちがってくる。

ゲーム屋さんって往々にしてそういうもんなんだけど,ゲームを制作するにあたって,おどろくほど貧弱なカーネルの上での実装を強いられることがある。そういう環境では,マルチスレッドとかあったとしてもとてもお粗末なものだったり,とんでもないバグ付きだったり,へたするとまったくサポートされていなかったりすることもある。

マルチスレッドやダイナミックリンクが使えなかったところでゲームは作れるし,今までも多くの場合はそうしてきたんだけど,だからといってこれらの機能がいらないってわけでは決してない,って僕はおもう。

線形的なシーケンスを記述する場合にマルチスレッドは便利だとおもうし,定型化できない多くの処理が存在する場合(FFのバトルイベントとかいい例じゃないかな),ダイナミックリンクがないと,とんでもないプログラムサイズになってしまうだろう。

こういう場合,高等なスクリプト言語を用意することで,要求を間接的に満たすことができる場合がある。コンテキストを多重化できるスクリプト言語をつかえば,簡易マルチスレッドみたいなことができるし,たいていのスクリプト言語は実行時にプログラムをロードするから,ダイナミックリンクみたいなことも問題ないだろう。

第3の動機では,スクリプトはプログラム本体の代替にしようとしているのだから,Cで組むのとおなじくらいの汎用性と実行効率が求められる。そういうことを考慮すると,ランタイムが重くて何かと制限の付きやすいインタプリタ型の処理系はあんまし好ましくないとおもう。外部コンパイラを使ったバーチャルマシンタイプの処理系のほうが理想的なんじゃないかな,って考えている。


今日はついでに第4の動機も。

第4の動機は,Cはさすがにつらくなってきたけど,C++はもっと嫌だ。だからもっとクリーンな言語処理系を。それだけ……。


バージョンアップ

2001-08-02

机の下から目覚めると,Doxygenが1.2.9になっていたので,おもむろにバージョンアップ。更新間隔が狭いなあ。開発者のやる気のなせる技かな。

Doxygenは意外と使えるツールで,ライブラリリファレンスを生成するっていう本来の目的以外にも,単にドキュメントを整形するためのツールとしても,なかなか使える。Doxygenのホームページ自体がDoxygenで生成されているんで,あんな感じのが簡単に作れるってことだとおもえばいい。

常に最新版をWindows/Mac/Linuxへ対応させていたり,新機能の追加に対して貪欲だったり(最近はXML出力に対応しようと躍起みたい)と,開発者のやる気を感じられるので,こっちもしばらく使いつづけてみようかな,って気になってくる。

http://www.doxygen.org/


Smallと,またちょこっとたわむれる。

けっきょく,

#define strnicmp(a,b,c) strncasecmp(a,b,c)

の一行をsclinux.hに追加するだけでmakeが通るようになった。引数無しで実行すると落ちるのが気にくわないけど,とりあえず動作はしているみたいなんで,気にしないことに。

amx(ランタイム)のほうは問題なくビルド完了。サンプルのハノイの塔も問題なし。

次は,外部アプリへの組み込みをためしてみようかな。


SDL, Abuse

2001-08-03

いままでSDLにはまったく手を出さずにいたんだけど,ちょっと興味が湧いてきたんで,ちょいと試してみることにした。

http://www.libsdl.org

mingw32推奨って書いてあるんだけど,入れるのめんどいし,ふたつの環境を混在させるのがあんま気持ちよくない(バージョンアップがかったるそうだなあ,とか)ので,とりあえずcygwinでやれるとこまでやってみることにした。

とりあえず'./configure; make'。いいかんじでコンパイルが通ってくんだけど,中盤でストップ。どうやらパス名にスペースが入ってるのがダメらしい。'My Document'をホームにしてるんで,そこがひっかかっちゃってるのだ。うー,素直に/homeにホーム置いときゃよかった……。

/tmpに移動し,気をとりなおしてビルド再開。こんどは問題なく最後まで通る。DirectX非対応になっちゃったみたいだけど(ヘッダ入れてないしね),そこらへんは次の機会にこだわるとして,いまはとりあえずよし。さっそく'make install'。

testディレクトリに入ってconfigureをかけるもSDL.dllがみつからなくてストップ。うー,/usr/local/libにインストールされたのか……。速攻でパスを通して'./configure; make'。こんどは大丈夫。テストプログラムは正常にうごいてるようにみえる。


SDLのリンク集のなかにSDL Abuseってのがあって,そういえばそんなゲームもあったなあ,とおもいつつgoogleしてみると,Windows用Abuseのバイナリがみつかった。

http://www.uidaho.edu/~scot4875/

僕がはじめてLinuxに触ったころって,どのディストリビューション(当時はSlackwareが有力だった)にかならずDoomとAbuseが付いていて,多分に漏れず僕もプレイした記憶があるんだけど,なんかすごいなつかしいなあ,っておもった。いま遊んでもそこそこおもしろいとおもう。

ちょっとフレームレートが低いのが気になるけど,これで最大速度ってことなんだろう。当時は,モード切り替えのたびにスワップしたり,敵キャラが出てきたとたんに超低フレームレートになったりしながらも遊んでたっけなあ。


電気街に行く

2001-08-04

某電気街におもむき,おもむろに携帯を解約。請求書がしばらく来なかったんでほっといたら,いつのまにかサービスが停止されちゃってたんだけど,どうせあんまり使わないんだし,って解約してしまったのだ。

ちなみに請求書が来なくなってたのは,住所登録が微妙にまちがってたのが原因らしい。いままでは大丈夫だったんだけどなあ。まあ,わざわざ変更しなおしてまで使いつづける気もしなかったのだ。

iモードとかもけっきょくぜんぜん使わなかったし,つぎはシンプルにPHSにでもしてみようかな,っておもう。


ついでに,あんま関係ないんだけど,Niftyも解約。ずいぶん長いあいだ放置してた気がするなあ。えーと,あとなんか解約するもんあったっけ……。


解約ついでに電気街でお買いもの。OverTopで"Serious Sam"と"Panzer General II"を購入。さっそく家に帰ってインストールしてみたんだけど,Panzerのほうは,なんだか正常にうごかない。Win2k非対応ってことか……。ダメダメだ。

http://www.panzergeneral.com

"Serious Sam"は,問題なし。むしろ快適。バカゲーのわりにはまともに作ってある気がするなあ。DukeNukemを,もうちょっと脱力気味にしたかんじ。強力な武器が手に入ると,もうちょっとおもしろくなってくるのかもしれない(また序盤なんで)。

http://www.croteam.com


ゲーセンで鉄拳4を初見。フリッカーはなかったけど,走査線の狭間が見えるんで,インターレス出力っぽい。けっきょく,システム246でVRAM増えてるってのは,まったくの嘘だったんだろうか。

鉄拳4もVF4も,ビジュアル的にはそんなにインパクトなかったんで,とりあえず格闘Xに期待しとこうとおもった。


SDLとMAD

2001-08-05

SDLがいい感じで動いてくれたので,これからはSDLを軸に開発を展開してみようか,っておもいはじめた。

そこでまずは,MAD(MP3デコーダ)とSDLを使ってMP3を鳴らす実験。これは,MADの出力をそのまんまSDLのオーディオに流し込むだけなんで楽勝だとおもったんだけど,けっきょく,ちょっと手間取ってしまった。

まず困ったのが,両ライブラリともコールバックで駆動するかたちになっていること。おのおののライブラリが勝手なタイミングで勝手な量の処理を要求してくるんで,そのあいだの整合性をとるのがめんどくさいのだ。最初はリングバッファとかダブルバッファをつかって非同期処理を目指してたんだけど,どうにもしっくりこないんで,けっきょくはセマフォをつかって同期を取るようにした。

もちろん,セマフォの制御はSDLのスレッドAPIを使った。最低限のライブラリといいつつもマルチスレッドAPIが用意されているあたり,このひととは気が合うのかもしれないなあ,っておもった。

あと気になったのが,MADのドキュメント不足。READMEには「仕様が頻繁に変更されるんでドキュメントは用意していない」なんて半ば脅しみたいなことが書いてあって,先が思いやられるかも。でも,このクリーンな設計はちょっと気に入ってたりするんで,しばらく付き合ってみようかとおもう。


ゲーセンでVF4を初見。雑誌の画面写真なんかでは,過剰なスペキュラの鋭さが気になってたんだけど,動いてる画面ではさほど気にならなかった。

スペキュラが鋭くて気になる,ってのは,ポリゴンの分割数が低いのにスペキュラを鋭くすると,ポリゴンのスジがでてしまって見苦しくなる,って現象のこと。GT3の路面スペキュラとか,特にやばいことになっとります。

これは,per-vertexでスペキュラを付けている限りどうしようもないんだけど,XBOXではper-pixelオペレーションによって根本的に改善できるってことになってるわけで,それがどんなもんになるのか,ちょっと期待している。格闘Xのバンプを使ったスペキュラ表現とか,純粋にすごいなあっておもうし。


VF4で,雪や砂にモディファイをかけているのが,ひそかに偉いなとおもった。PS2なんかだとDMAデータの広範囲に変更をかけるのは「基本的な避けるべき事項」なわけで,こういったモディファイはなかなかやりたがらないとおもうんだけど。頂点インデクスとかも,あんま流行らないしね。

かといって,NAOMI2だってタダでモディファイできるってわけじゃないんだから,PS2でそれをやらないってのは,ひとえに開発者の怠慢なのかもしれない,っておもった。


SDL for PS2Linux

2001-08-06

今日から会社は夏休み。なので,職場には人がまばら。だからいつもよりちょっとネムめに仕事した。

おもむろにSDLをダウンロードしてきて,PS2Linuxにほうりこむ。で,仕事している裏でコンパイル。PS2だとコンパイルが遅いんで,ひと作業終えたころにやっとビルド完了ってかんじだ。

SDLはいちおうPS2Linuxに正式対応しているんで,なにも考えずに'./configure; make; make install'で問題なし。サンプルのなかには微妙に動かないのもあったけど(GLとかgammaとか),まあ,ほぼ問題なく動いてるみたいだ。

勢いにのってAbuse-SDLやLsdlDoomをダウンロードしてビルドしてみる。どちらも'./configure; make'でまったく問題無し。やけにあっさりと通ってしまったので,なんだか逆に拍子抜けしてしまった。

Doomは,たまにがくがくと処理落ちするけど,わりとまともに動いている。PS2はメモリアクセスが高くつくきらいがあるし,まったくカスタマイズされてないフルCのコードで動いているんだろうから,まあ,こんなもんだろうってとこ。

Abuseはなめらかに動いてるけど,PS2版SDLの最低解像度が640x480なんで,ちょいと画面がきゅうくつだ(Abuseは320x200で動いている)。ここはぜひともNTSC出力してみたいところ。やっつけでSDLのソースをいじるのはそんなに難しくなさそうなので,暇があったらかまってみたいけど……どうかな。

でもその前にマルチAV/ビデオ分岐ケーブル買って来ないとケーブルさしかえがめんどくさくてしょうがない。標準添付のケーブルはマルチAV→Dsubだから,NTSC出力を見ようとおもったら根っこからケーブルをつけかえなきゃいけないのだ。

LsdlDoom - http://firehead.org/~jessh/lsdldoom/

Abuse-SDL - http://www.labyrinth.net.au/~trandor/abuse/


サエキけんぞうのネットラジオ番組を毎週なんとなく聴いてるんだけど,先週のゲストで出てたSPANK HAPPYの曲がなんとなくよかったな,っておもった。こうやって書き残しておかないと,すぐに忘れちゃうんだよね。あの番組,過去の放送は配信してないし。

http://www.radiat.net/bangumi/saek.html

ちなみに,2chのひろゆきの番組も,なにげに毎週聴いてる。


静かな一日

2001-08-07

今日も職場にはひとがまばら。最近,個人的に仕事をかかえこみ気味だったんで,こんな状態でもやることは山ほどある。ちょっとネムくなりながらもしこしことコードを打っていた。

ふとflipCodeをみてみるとDoxygenの1.9.2.1がリリースされているとのこと。さほど重要そうでもないんで今回は見送り。


ふとGamasutraをみてみるとcover featureが更新されていた。題目をみるとデータの復活術っぽいんだけど,中身はデータ吸出し術って感じだ。うーん。ゲーラボじゃあるまいし……。

著者いわく,そのむかし,ローカライズや移植の仕事の際にこういう作業が必要とされたってことらしいんだけど,下請けにぽいっと丸投げしちゃうようなやりかただと,こういう苦労も絶えないんだろうなあ,と,ちょっと偲んでみた。


最近よく,オブジェクト(キャラクター)間の相互干渉処理ってむずかしいなあ,って痛感させられることがある。ここらへんの考え方ってのをなんとか体系づけて整理できないものかとずっと考えてるんだけど,いまだに回答が見えてこないっていうか,うまくいかないのだ。

たとえば,ふたつの相互に参照し干渉しあってるオブジェクトがあったとする。こいつらを1フレーム先の状態にもっていくとして,どちらを先に処理してやるのが正しいだろうか。互いに参照しあってるから,どういう順序で処理するかによって結果はことなってしまう。

僕はいまんところ,フレームの最初にお互いの公開情報をどこかに保存しておいて,処理をすすめる際にはその保存された公開情報をもとに干渉処理をおこなう,って方法を突き詰めてみてるんだけど,これもやっぱりちょっと中途半端だ。

この方法だとたしかに処理順序の問題は解決できるんだけど,それでも特殊な処理ではどうしても順序付けが必要になってくる場合があるし,(それだったら最初から順序付けを厳密にしたほうがいいんじゃない?),干渉について実際に影響が出るのが1フレーム遅れてしまうって問題もある。


ウェブ整形スクリプトをちょっと整理して,日記の過去ログ機能とかもつけてみた。まあ,こんなもんかな。


MIPS

2001-08-08

むしょうに眠い。こんなふうに眠くなるのって,たいてい,複雑なしくみを考えているときとか,なかなか取れないバグをむりやり取ろうとしているときとか,そんな感じなんだけど,このとき眠いのは後者のほうで,そうとうむかしに書きちらした記憶のあるインラインアセンブラだらけの関数群からバグを取っている最中だった。

けっきょく原因はベクトルの正規化をひとつ忘れてただけだったんだけど,コードがあまりにも意味不明だったんでやけに苦労してしまった。きっと,このコードを書いたときも,いまみたいに意識朦朧になりながら作業してたんだとおもう。


いつもアセンブラを書くときはインストラクション表とにらめっこしながらてきとうに書いてるんだけど,そもそもちゃんとMIPSを勉強したことがないのもダメなような気がしてきたので,ちょっとMIPS関連の資料をあさってみることにした。

さっそくMIPS Technologiesのホームページにいってみるとよさげな資料がいくつか転がっている。これなら書籍をあたってみなくても十分ことたりるかもしれない。

MIPS64 5K(TM) Processor Core Family Software User's Manual - http://www.mips.com/declassified/Declassified_2000/MD00012-2B-5K-SUM-02.06.pdf

EEはMIPS64の拡張ってことになってるみたいなんで,ここらへんが該当資料になるのかな。

Core Coprocessor Interface Specification - http://www.mips.com/products/MD00068-2B-COPROC-SPC-01.12.pdf

これはとくに見なくてもよさそうだったんだけど,FPU/VU0のことをCOP1/2ってよぶ理由がわかって,ちょっとうれしかった。

MIPS64(TM) Architecture for Programmers Volume I: Introduction to the MIPS64(TM) Architecture - http://www.mips.com/declassified/Declassified_2001/MD00083-2B-MIPS64INT-AFP-00.95.pdf

Volume II: The MIPS64(TM) Instruction Set - http://www.mips.com/declassified/Declassified_2001/MD00087-2B-MIPS64BIS-AFP-00.95.pdf

Volume III: The MIPS64(TM) Previleged Resource Architecture - http://www.mips.com/declassified/Declassified_2001/MD00091-2B-MIPS64PRA-AFP-00.95.pdf

ここらへんはアーキテクチャの解説書。

MIPSpro(TM) Assembly Language Programmer's Guide Volume 1 - http://www.mips.com/Documentation/MIPSPro_Ass._Lang_Vol1.pdf

MIPSpro(TM) Assembly Language Programmer's Guide Volume 2 - http://www.mips.com/Documentation/MIPSPro_Ass._Lang_Vol2.pdf

じつはこれがいちばん役にたつんじゃないかなっておもう。けっきょく,いちばん知りたいのはアセンブラの書き方だから……。


まだDOSなんかでx86系のアセンブラを書いてたころ,RISC vs CISCっていう,いわば宗教論争みたいなのがあって,そのなかで「CISCのほうがアセンブラを手で書きやすい」なんて論説があったような気がするんだけど,じっさいにMIPSに触れていると,いやそうでもないんじゃないかなあって気がしてくる。

x86の多種多様なアドレッシングとか,あれはあれで便利だったかというと必ずしもそんなじゃなかったような気がするし,memory to memoryオペレーションとかだって,レジスタさえあまってればどうにでもできたとおもう。

だいいち,あのころのx86って,スループットやらレイテンシやらインタロックやら,遅くなる原因がめちゃくちゃに絡まっていて,強力なオペレーションも結局は禁じ手になってたりして,今にしておもうとほんとたいへんなCPUだったなあ,っておもう。

MIPS系のCPUはインストラクションは少ないけどそのぶんシンプルでわかりやすいし,パイプラインが単純なぶんインタロック/ハザードの類も予想しやすくて,むしろこっちのほうがアセンブラに向いてるんじゃないかなあ,っておもうのだ。

そのむかしx86では,スタックポインタまで汎用レジスタのかわりとして使ってみたりとか,みんなとんでもない苦労をしていたような気がするんだけど,あれはいったいなんだったんだろうって考えると,ちょっと脱力する。まあ,あれはあれでおもしろかったんだけど。

ところで,CISCってRISCに対するアイロニーとして生まれた単語なんだから,分類としてCISCって言葉をつかうのはおかしかったな,っておもった。


autoconf

2001-08-09

今日はひさしぶりにコンビニ食品で昼食をすませた。コンビニめしってゴミがでるんであんま好きじゃないんだけど,みんな夏休み中でいっしょに食いにいくひともいないんで,てきとうにコンビニめしなのだ。

う,自販機のコーラが売り切れてる。夏休みだから自販機の補充も止まっちゃってるんだな。コンビニで買ってくりゃよかった……。


なんとなくautoconfを習得してみようとおもい立った。いままではプラットフォームごとにMakefileを用意したり,ソースのなかにしつこく#ifdefを入れこんだりしてたんだけど,どうせSDLでお手軽マルチプラットフォームをめざすなら,せっかくだからautoconfを使ってみなければ,って考えたのだ。

autoconf自体はperlで作られているみたいなんだけど,各ファイルのテンプレートはm4っていうマクロプロセッサで処理されて,最終的に出力されるconfigureはシェルスクリプトになっている。この複雑な組み合わせっぷりが,じつにUNIX的だなあとおもう。

m4って,名前はよく聞くんだけど触ったことは一度もなかったので,とりあえずこいつから調べてみることにした。どうやら,もともとはFORTRAN用のプリプロセッサとして使われていたもので,ようするにccに対するcppのような存在らしい。機能的にはcppよりもちょこっとよさげな感じがする。基本的にはマクロ展開しかしないんだけど,算術計算や外部コマンドの呼びだしとかもできるようになっているみたいだ。

m4 online manual - http://www.gnu.org/manual/m4-1.4/html_mono/m4.html

で,autoconfも基礎はおさえたんで,いざconfigureのテンプレートを書いてみようかとおもったんだけど,シェルスクリプトで条件判定(if)する方法が思い出せない。うーん,最近はほとんどpythonに頼ってるからなあ。


そんなかんじで,手さぐりしながらなんとかできたのが,MADライブラリのインストール状態をチェックするところまで。

AC_INIT(test.c)

AC_PROG_CC

AC_MSG_CHECKING([for MAD version 0.13])
have_mad=no
AC_TRY_COMPILE([
#include <mad.h>
#if MAD_VERSION_MAJOR != 0 || MAD_VERSION_MINOR != 13
#error bad version
#endif
],[],[
have_mad=yes
])
AC_MSG_RESULT($have_mad)

if test x$have_mad != xyes; then
  AC_MSG_ERROR([*** MAD version 0.13 is required])
fi

AC_OUTPUT()

これをconfigure.inって名前で保存してautoconfするとconfigureが作成される。そのconfigureを実行すると,MAD v0.13が見つかればつつがなく終了して,見つからなかった場合はエラーを出して止まる。たったそれだけなんだけど,ここまで来るのにずいぶん苦労してしまってような……。まだぜんぜん勘がついてないんで,しばらくは手さぐりで書いてくことになりそうだ。

けっきょくautomakeにはまったく手がついてない。道のりは長いなあ。


筐体依存

2001-08-10

夏休みも今日でおしまい。夏休みっつっても毎日出勤してたわけですが。

夏休み中は職場にほとんど人がいなかったんで,ひさしぶりにひきこもりスタイルでプログラミングすることができた。やっぱり周囲にだれもいないのって集中しやすいかもなあ,っておもった。なんていうか,なんともいい知れない安心感があったのは,なんでだろ。やっぱり,素がひきこもりがちなのかなあ。とほほ。これでまた元の状態の職場にもどったら,ちょっと調子狂うかもしれない。


'Game Programming Gems 2' がでてることに初めて気がついた。なんだ,いつのまに出てたんだ。さっそく注文しようかな。

http://www.amazon.co.jp/exec/obidos/ASIN/1584500549/ref=sr_a...


http://www.watch.impress.co.jp/game/docs/20010809/maxpayne.h...

ここのMAX PAYNEの紹介記事を読んでいたら,なにげに欲しくなってきた。ちょっとあなどっていたかもしれない。だって主人公の顔があんなに濃いんだもん(イラストのほうだと全然濃くないんだけどなあ)。バレットタイムシステムとかも,かなり奇抜っていうか,奇妙だし。

まあ,買ったとしてもやる暇無いだろうなあ。今月はデビルメイクライで精一杯だとおもうのだ。


金曜日ぐらい早めに切り上げるか,ってことで,区切りのいいところで仕事は上げて,おもむろに新宿西スポにいってみた。てきとうに遊んだあとに,なにげなく鉄拳4をのぞき込んでみたんだけど,やけに画像がくっきりしてることに気がついた。あれ,これハイレゾじゃん……。

どうやら僕が以前地元のゲーセンで見た「ローレゾな」鉄拳4ってのは,低解像度モニタを使っているせいでローレゾになってたんであって,出力自体はハイレゾも用意されているようだ。高解像度ディスプレイだとジャギーが見えるくらいくっきりした画像になっている。

しかし,セガのバーサスシティ(セガの対戦専用筐体)だとハイレゾになるのに,ナムコの筐体だとローレゾになっちゃうってのは,なんとも皮肉だな,とおもった。ナムコってずっとPS互換基盤を使ってたから,筐体もローレゾだったりするのかな。


おもに戦争関連

2001-08-11

雨の音で目をさます。時計を見るともう6時過ぎだ。こんなに豪快に寝たのは久しぶりかもしれない。てきとうにメシを食って,てきとうにゲーセン行って,てきとうにDVDなぞを買ってみたりして……。ほんとうに何もない一日だとおもった。


土曜の夜をまったり過ごそうとおもって,なんとなくDVDを買ってみた。買ったのは「シン・レッド・ライン」。よくかんがえるとぜんぜんまったりしてない映画なんだけど,まあおもしろかったんでよしとしたい。ただ,170分もある映画なんで,さすがに疲れてしまった。それでいてなかなかエグい戦争映画だったりするわけで。もうお腹いっぱいです。


「パンツァー・ジェネラル」がWin2kで動かないのが釈然としないんで,かわりに「大戦略」でもやってみようかと,システムソフトのホームページからいろいろ体験版を落としてみた。しかし体験版をプレイしてみると,ますます釈然としない感じに。うーん,大戦略ってこんな派手なゲームだったかなあ。

漠然とわきあがる違和感を確認しようと,HDDの奥からエミュレータをひっぱり出してきて,いにしえの「大戦略88」を起動してみた。兵器の国家分類はないし,自軍のユニットを通り越せなかったり,索敵も遠距離攻撃もなかったりと,いまどきのストラテジーと比べたら貧弱そのものっていうか,当時でさえそうおもっていたぐらいなんだけど,今にしてみるとそのシンプルさが微妙に気持ちよかったりするなあ,とおもう。

ひとむかし前のPCゲームって,ルールが複雑だったり扱える情報量が多かったりするほど優れてる,みたいな風潮が流れてて,そのあおりを受けて肥大化してった結果,破綻をきたして自滅したゲームってのがいくつかあるとおもうんだけど,大戦略なんかはその典型的な例なんじゃないかな,っておもうのだ。あとは光栄の三国志とか信長の野望とか……。僕は三国志3のあたりで脱落しちゃったんで,最近のはよく知らないんですけど。


automake

2001-08-12

先日にひき続き autoconf のお勉強。こんどは automake を使ってみることにした。

autoconf (configure) は Makefile.in をもとに Makefile を生成するんだけど,この Makefile.in も自動生成しちゃおうってのが automake の趣旨のようだ。ということでまずは,Makefile.in の元となる Makefile.am を作らなきゃいけない。

bin_PROGRAMS = hoge
hoge_SOURCES = hoge.c

とりあえず Makefile.am はこれでOK。

次は configure.in に automake の設定を書き加えていく。まずは automake の初期化を AC_INIT の直後に追加する。

AM_INIT_AUTOMAKE(hoge,0.0)

第一引数がパッケージ名で,第二引数がバージョン名だ。次に AC_OUTPUT(出力ファイルリスト)に Makefile を追加する。

AC_OUTPUT([Makefile])

configure.in はこれで終了。

最後にコマンドラインから

> aclocal

と実行する。このとき,automake 関連のマクロを含んだ aclocal.m4 が自動的に生成される。ちなみに aclocal.m4 ってのは configure で使う自分専用のマクロを定義するファイルなんだそうだ。

で,さっそく automake をかけるんだけど,不足しているファイル(install-shとか)をおぎなうために -a -c オプションを併用する。

> automake -a -c

最後に autoconf で完了。


これでとりあえず動いたんだけど,automake のときにいろいろとファイルがコピーされたせいでディレクトリがごちゃごちゃになってしまった。このままだとちょっと作業しにくそうなんで,ソースは src というサブディレクトリに独立させることにした。

で,けっきょくこんな感じになった。

configure.in:

  AC_INIT(src/hoge.c)
  AM_INIT_AUTOMAKE(hoge,0.1)

  AC_PROG_CC

  AC_SEARCH_LIBS(mad_decoder_init,mad,[],
    AC_MSG_ERROR([*** MAD version 0.13 required])
  )

  AC_OUTPUT([Makefile src/Makefile])

Makefile.am:

  SUBDIRS = src

src/Makefile.am

  bin_PROGRAMS = hoge
  hoge_SOURCES = hoge.c

うーん。便利といえば便利かもしれない。まだあまり恩恵にはあずかれてないけど。


mlvwm

2001-08-13

010813s.png

どうやら世間様では今日からが盆休みということのようで,朝の急行列車もスカスカで快適に出社することができた。いつもは肩をよせあうような混みぐあいだからなあ。朝のラッシュは避けてオフピーク通勤しているにもかかわらずあの混みようなんだから,とんでもないよなあ,っておもう。


なんとなく,端末として使用しているPS2Linuxにmlvwm(Macintosh Like Virtual Window Manager)を入れてみた。

この前までは軽い速いと評判のXFCEを入れて使ってたんだけど,けっきょくXFCEが軽いといわれているのも,GNOMEやKDEなどの重厚なデスクトップ環境にくらべたらわりと軽いですよって程度のもんで,絶対的に見てそれほど軽いってわけではないようだ。いまどきのPCとくらべたらかなり貧弱な環境であるところのPS2Linuxにとっては少々荷がおもいかもしれない。

そこでほかのウィンドウマネージャに切りかえようかとおもったんだけど,twmやfvwmってのもちょっとありきたりだったので,おもいきって変りだねのmlvwmを試してみることにした。

おもむろにアーカイブをダウンロードして展開してみると,configureではなくてImakefileが入ってる。なんとなく懐かしい気分になりながらも'xmkmf; make; make install'。もはや当然のようにコンパイルは通っていき,今回もやけにあっさりと作業完了。こうも簡単にPS2で動いてしまうと,まあ当然のことではあるんだけど,ちょっとすごいかも,っておもう。

mlvwmはなかなか快適に動いている。機能的にはごくふつうのウィンドウマネージャなんだけど,そもそもxterm/ktermぐらいしか使ってないので,こんなもんで十分だろう。どうせまた数ヶ月後には別のデスクトップを試しているんだろうけど,とりあえずそれまではmlvwmを使ってみようとおもった。

mlvwm - http://www2u.biglobe.ne.jp/~y-miyata/mlvwm.html


デフォルト引数

2001-08-14

今日はなんとなくpython日和。煮詰まり気味なメインプログラムから離れて小粋なスクリプトをチマチマと組み立てるひとときは,プログラミングのプリミティブな楽しさをおもいださせてくれるのだ。っていうか,たんなる現実逃避なんだけど。

そんなわけでpythonを使ってCのコードを生成するツールを作っていたんだけど,ひとつおおきな落とし穴にはまってしまって,今日のうちに終えるはずだった作業を明日まで持ち越すことになってしまった。うーん,こんなところにこんな罠がひそんでいるとは……。

たとえばこんな関数があるとする。

def afunc(list=[]):
    list.append('*')
    print list

リスト(mutable)の引数をひとつ取り,その後ろに'*'をひとつ追加してprintするだけの簡単な関数だ。引数を与えなかった場合は空のmutableをディフォルト引数として使う。ので,

afunc()
afunc()
afunc()
afunc()

なんて感じのコードを実行すると

['*']
['*']
['*']
['*']

という結果になる……のを期待してたんだけど,実際は

['*']
['*','*']
['*','*','*']
['*','*','*','*']

こうなってしまう。

これは,pythonのディフォルト引数は関数が定義されたときに一回だけ評価される,という仕様からきているようだ。つまり,このスクリプトが実行された瞬間に

[]

って式が評価されるんだけど,これは空のmutableオブジェクトが作成されて,そいつへの参照が返されることになるので,引数listのディフォルト値は「空のmutable」ではなく「どっかに作られたmutableオブジェクトへの参照」ってことになる。で,けっきょく,afuncを呼ぶごとにそのmutableに対してappendを行うことになる,ってわけだ。

python online manualより - http://www.python.org/doc/current/ref/function.html

pythonにはだいぶ慣れたつもりでいたんだけど,まだぜんぜん落とし穴があるなあ,とおもった。ちゃんと勉強せねばなりませぬ。


PSION revo

2001-08-15

010815.png

昨日,通勤中に読んでいた小説を読み終ってしまったんで,今日はマイPDAことPSION revoをポケットの中につっこんで出勤することにした。revoを持ち歩くのはちょっとひさしぶりで,というのも,最近こいつの調子が微妙におかしいのだ。どういう原因で起こるんだかわからないけど,ときどき電源が断続的に落ちるような状態になってしまう。ACアダプタをつなぐと動作が安定するんで,どうやらバッテリーがあやしいらしいことはわかる。ので,とりあえず完全放電してからしばらく寝かせてみることにしたのだった。

日本ではかなりマイナーというか,ほとんど知られていない部類に入るPSION社なんだけど,ヨーロッパでは比較的有名なPDAメーカーだったらしい。ところが,最近では欧州市場でもわりとつらい立場になってきたようで,今後コンシューマPDA市場からは撤退するってはなしもあったりする。

僕的には,横80文字表示できるってのがPDAの第一前提としたいところなんだけど,その前提をキープしつつポケットに入るサイズのPDAってのは,いまんところPSION revoしか見たことがない。まあ,なんか代わりの製品が登場すればそれでいいんだけど,それまではPSIONにがんばってもらいたいものだなあ,とおもった。


ASSEMBLY'01

2001-08-16

そういえばASSEMBLY'01が終わったんだよなあ,と,なにげにftp.dti.ad.jpをチェックしてみると,incomingにasm01の作品がアップされていた。さっそくデモ総合2位のgerberaをダウンロード。あとは,仕事中のBGMにでもしようかと,てきとうにMP3作品をみつくろってダウンロードしてみた。

gerberaは,DemoPajaっていうデモ用オーサリングツールで有名なmoppiの作品。この作品も多分にもれずDemoPajaで作られているみたいだ。で,さっそく見てみたんだけど,内容は,まあ,なんというか,まあまあ。ちょっと重い,っていうか,豪勢すぎるっていうか,もうちょっと余裕みたいなものが感じられるといいのにな,っておもった。

これはなんにでも言えることなんだけど,持てる限りのリソースをフルに使いまくるにも,ちょっとした余裕を感じさせるのって大事だとおもう。

HDDが超音速の唸りをあげながら高速回転し,怒涛のポリゴンの嵐が画面を埋め尽くし,大興奮のMP3がドコドコと猛りをあげ,バンプやら環境マップやらが強烈な自己主張を発しまくって……,とか,そんなノリもまあいいんだけど,どうせなら,スマートに涼しく余裕っぽく「おれたちこんなんやっちゃってますけど実はまだ余裕なんスよねー」みたいなのを見せつけられると,すなおに圧倒させれるなあ,っておもう。

だから,Teslaとか(涼しげにαブレンディングまくり),heaven7とか(涼しげにレイトレ),そういうのが好きかもしれない。あと,KanoさんのBumpWaterとかも,そういう部類に入るんじゃないかなとおもう。電球をクリックするとプチって消えたりするところとか,ちょっとした余裕だとおもうのだ。


ダウンロードしたMP3のなかに,個人的に応援しているaisthの新曲が入っていた。aisthは元komplexのjugiが主催する音楽ユニット。おととしあたりからプロデビューをめざして活動しているっぽいんだけど,なかなか進捗がなくてちょっと心配になっていたのだ。まあでも,新曲をasmに出展するぐらいなんだから,大丈夫なんだとおもう。新曲もなかなかいい感じ。これからに期待してみたいとおもった。

aisth - http://www.aisth.com


Lua

2001-08-17

プログラムのある部分でスクリプト制御の必要性がでてきた。ということで,ちょっとLuaの勉強をしてみることにした。プログラム本体への組み込み作業は他のプログラマさんの手によってすでに完了しているんで,僕はさらっとさらう程度にお勉強って感じだ。


まず最初は,Cで作った関数をLua側から呼びだすテスト。

#include <stdio.h>
#include "lua.h"

static int print(lua_State *L)
{
    puts(lua_tostring(L,1));
    return 0;
}

int main(void)
{
    lua_State *L=lua_open(0);
    lua_register(L,"print",print);
    return lua_dofile(L,"test.lua");
}

printという名前の関数をLuaに登録したあとに,test.luaというファイルを実行している。test.luaは,まあたとえばこんな感じ。

print "hello world!"

これを実行すると

hello world!

こうなる。


こんどは逆にLuaで作った関数をC側から呼んでみる。まずはLuaファイルから

function foobar(x,y)
    return x*y
end

次にCファイル

#include <stdio.h>
#include "lua.h"

int main(void)
{
    lua_State *L=lua_open(0);
    lua_dofile(L,"test.lua");
    lua_getglobal(L,"foobar");
    lua_pushnumber(L,5);
    lua_pushnumber(L,7);
    lua_call(L,2,1);
    printf("%f¥n",lua_tonumber(L,1));
    return 0;
}

実行すると

35.000000

ようするに,関数への参照,引数,の順でスタックに積みあげてからlua_callを呼ぶと,返値がスタックに積みあがった状態で戻ってくるのだ。ちなみに,lua_callに渡している"2,1"は,引数の個数と返値の個数をそれぞれ意味している。

とりあえず基本はこの二つ。Luaを本格的な制御に使うんじゃなくて,簡単な条件判定とか程度に使うんだったら,ほんとうにこの程度を押さえておけば十分だとおもう。


僕的にLuaは,多重化できないという点で「かなり惜しい」感じなんだけど,あえてその点を無視すれば,組み込み用スクリプト言語として非常に優れたライブラリだとおもう。

この手のライブラリって,気軽に組み込むにはちょっと大きすぎたり(guileとか),もしくは,小規模なんだけどちょっと完成度が低くすぎて,組み込むまでにもそうとうの改造が必要そうだったり,とか,そんなのが多いんだけど,Luaは,小規模,軽量,高速,と組み込み言語として重要な点をしっかり押さえつつも堅実な作りをしているのが特徴だ。

ライセンス的にも非常に使いやすく(いわゆるBSD的ライセンスってやつ),実績もあるので安心して使えるのもポイントだとおもう。そんなわけで,業務上では,しばらくLuaとの付き合いが続きそうだ。

Lua Homepage - http://www.tecgraf.puc-rio.br/lua/


休日っぽい休日

2001-08-18

今日は学生時代の友人と飲み。場所は池袋。池袋なんてめったに行かないよなあ。そして,ひさしぶりに暴飲暴食をかます。そこのきみ,食ってないでちょっとは語らいたまえ,ってかんじで。

そして飲みの後はカラオケ。あるときは静かに,あるときは激しく,情熱のおもむくままに歌い暴れまくる。ていうか途中寝てたんであんま覚えてない。

カラオケが終わったんで帰ろうかとおもったら,かなりきわどい時間。東急線って意外と終電が早いのだ。すばやく金を払って駅までダッシュ。おかげで頭痛くなってしまった。アルコール入ったあとの運動はつらい……。


今日も飲み

2001-08-19

今日も飲み。でも今日のメンバーはちょいと濃い。げーはなさん,gridmanさん,POTOSさん,僕,の4人。メンバーにあまり脈略がないような気がするけど,いちおうデモシーンについて語らうって会合なのだ。

しかしながら,いざ封をきってみると,話の内容の95%はPOTOSさんことscene.jp.org氏のモテ話で,残りの5%が素晴らしきげーはなトークだった。なんていうか,自分のモテなさと無軌道さを反省する日だった。

POTOSさんは,なんというか,まったく噂どおりのうんざりするほどのモテ男子で,90分間に渡って「俺がいかにしてモテるのか」をとくとくと話された。そして5分間のトイレ休憩のあと,追い討ちをかけるかのように「君たちがいかにしてモテないか」を90分間に渡って話された。もううんざりだ(5%ぐらい嘘)。

あと,POTOSさんがモテ会社(POTOS社長以外の全員が女子社員という,まさに現代に舞い降りたユートピア)を設立したあかつきには,僕を男子社員2号にする約束をつけとくんだったなあ,と,帰りの電車のなかで後悔した。

げーはなトークでは,げーはなさんのもつ鋭い分析力が,素晴らしきその切れ味を今日も発揮しまくってた。なんていうか,僕はものごとを真面目に考えるのがきらいなので,こういうものごとを冷静に分析する能力をもった人と語らうのは非常に楽しいかもしれない。僕が言葉にできずにもやもやと考えていたことが,まるで魔法でもかかったかのように,その人の口からすらすらと語られてくのだ。

シンクタンクとかコンサルタントっていうのは,こういうことなんですかな,とおもった。考える能力を持たないひとのかわりに,ものごとを考えてくれる存在。そういうの。


再びLua

2001-08-20

Luaでは,Luaとホストプログラム間のやりとりは,ほとんどがスタックを通しておこなわれる。関数の引数なんかはlua_pushnumberとかで積みあげて,いらない返値なんかはlua_popでスタックから追い出す。ここらへんは基本。

Luaスクリプト中のグローバル変数をホストプログラム側から参照するには,lua_getglobalを使う。lua_getglobalは,指定されたグローバル変数をスタックにpushする関数だ。スタックに積んだら,lua_tonumber(スタックの先頭の値を数値に変換して返す)とかで参照すればいい。用が終わったらlua_popだ。

グローバル変数の値を書き換えるには,ほぼ逆の手順をふむ。lua_pushnumberとかでスタックに値を積んだあとに,lua_setglobal(スタックからpopして指定された変数にストアする)を呼べばいい。

そんなわけで,たとえば,

hoge = a_func(3,bar(10),foo)

に相当するコールをホストプログラムから発行するには

lua_getglobal(L,"a_func");
lua_pushnumber(L,3);
lua_getglobal(L,"bar");
lua_pushnumber(L,10);
lua_call(L,1,1);
lua_getglobal(L,"foo");
lua_call(L,3,1);
lua_setglobal(L,"hoge");

こんな感じになる。まあ,

lua_dostring(L,"hoge = a_func(3,bar(10),foo)")

って書くのがいちばん楽なんだけど。


photon map

2001-08-21

なんか台風が来てるらしい。ぜんぜん知らんかった。でも雨は降ってないみたいなので手ぶらで出社。まったく問題なし。


会社に着くと,眠げにflipCodeを閲覧。Image Of The Dayによさげな雰囲気のスクリーンショットが上がってた。

http://members.tripod.co.uk/GHOSTMASTER_STUFF/

解説を読んでみると,ライトマップをphoton mapなる手法で生成しているんだとか。photon(光子ってことだろうけど)を光源から飛ばしてグローバルイルミネーションをもとめる手法らしい。

http://graphics.stanford.edu/~henrik/

雰囲気的にはレイトレの拡張みたいなもんで,コースティクスなんかもシミュレートできるらしい。ラジオシティよりも高速にグローバルイルミネーションをもとめることができるってことで注目されているらしいんだけど,もうちょっと調べてみないとよくわかんない。


よっしんさんのとこから超連射X68k for Windowsをダウンロード。

http://www2.tky.3web.ne.jp/~yosshin/

これが噂の超連射か,とおもわず涙した。ちなみに,僕の部署には超連射の2週目の最終ボスまで行けるひとが2人いた。


Small

2001-08-22

Luaにひき続き,Smallもちょっとまじめに取り組んでみることにした。

ちなみに,前回ちょろっとさわったころから1回バージョンアップがあって,Linuxで問題なくビルドできるようになっている。

まずは,ランタイムを使った最小限のサンプルを組んでみる。

#include <stdio.h>
#include <string.h>
#include "amx.h"

static cell AMX_NATIVE_CALL _testfunc( AMX *amx, cell *params )
{
    puts("Hello world!");
    return 0;
}

static AMX_NATIVE_INFO local_natives[] =
{
  { "testfunc", _testfunc },
  { NULL, NULL }
};

int main( int argc,char **argv )
{
    AMX amx;
    void *prog;
    cell ret;
    int err;

    memset( &amx, 0, sizeof(AMX) );

    {
        FILE *fp = fopen( "test.amx", "rb" );
        AMX_HEADER hdr;

        fread( &hdr, sizeof(hdr), 1, fp );
        rewind( fp );

        prog = malloc( hdr.stp );
        fread( prog, hdr.size, 1, fp );
        fclose( fp );
    }

    amx_Init( &amx, prog );
    amx_Register( &amx, local_natives, -1 );
    err = amx_Exec( &amx, &ret, AMX_EXEC_MAIN, 0 );
    while ( err == AMX_ERR_SLEEP )
        err = amx_Exec( &amx, &ret, AMX_EXEC_CONT, 0 );

    free( prog );
    return 0;
}

これを amx.c と一緒にコンパイルしてリンクする。amxcore.c などは使ってないので,amx.c だけでいい。ランタイムはこれで完了。次は,こいつに食わす Small のバイトコード test.amx を作成する。まずはソースファイル(test.sma)から。

native testfunc()

main()
  testfunc()

これをコンパイラ(sc)に突っこんで test.amx に変換する。

準備は以上で完了。実行すると

Hello world!

となる。


引数の受け渡しとかはまだ試してないんだけど,とりあえずわかったのは,ランタイムがかなり小さいってこと。標準ライブラリをまったく使わない素の状態なら amx.c だけで動作するんで,まあ20kB以下といったところ。

ほかにもJITコンパイラとか,いろいろと謎の魅惑的な機能がひそんでいる模様。まだほんのさわりの部分なんで油断はできないけど,わりと幸先いい感じじゃないかなあ,とおもった。


Devil May Cry

2001-08-23

ここ数日は,台風の影響か,わずかに涼しい日が続いてたんだけど,台風が去ったらまた一気に暑くなってきたようだ。まあ,こっちの方が夏らしくていいけど。

本日発売のデビルメイクライを速攻で購入。以前から楽しみにしていたタイトルだ。んで,さっそくプレイ。ザコ相手のバトルはなかなか爽快で楽しいんだけど,ボスが強くて泣けてくる。ここらへんの難易度のギャップは鬼武者のそれに似てるとおもう。しかも,DMCはボス前でセーブできるってわけでもないし,コンティニュー回数も限られてるんで,なかなかつらいのだ。

ゆっくり攻略してる暇もないんで,とっととイージーモード出してそっちでクリアしようかなあ,とおもった。


スタイリッシュ?

2001-08-24

スタイリッシュハードアクションことデビルメイクライことDMCを昨晩やりまくってたわけなんだけど,あまりのボスの強さに腹を立てつつスタイリッシュになりまくってたら,案の定,スタイリッシュに寝坊してしまった。やるせない。


きのう,通勤中に読んでた本を読み終えてしまったので,今日はPSIONの出番。先日チェックしていたphoton mapのpdfを転送して家を出た。この時点で遅刻確定してるんだけど,まあ,あまり気にせずに。

で,内容はさっぱりわかんないんだけど,どうやら,photon mapだけでバリバリとレンダリングするって内容ではなさそうだ。このpaperで解説している手法では,実際に画像をレンダリングするのは分散レイトレーシングで,その特定のレンダリングパスでphoton mapを適用することによって高速化をはかる,ってことらしい。

まず,コースティクスが出そうなところにphotonを集中砲火してコースティクスを求めてしまう(これはそのまま最終画像に使われる)。次に,シーン全体に対して比較的密度の薄いphotonをバラまいて,光の分布を求める。んで,その情報を元に分散レイトレーシングすると,なんだか知らないけどわりと速くレンダリングできるらしい。ここはとりあえず,分散レイトレーシングについて調べておかなきゃ理解できなさそうだ。

photon map自体がグローバルイルミネーションを求める手法なのかとおもってたんだけど,まだちょっとわかんない。

http://graphics.stanford.edu/~henrik/papers/ewr7/ewr7.html


キューブの「ゼルダ」は,いろんな意味でショッキングだった。「マリオ」は,単純に面白そう。個人的には「メトロイド」も期待なんだけど,周囲のウケは何故か悪い。なんでだ。

やっぱり,具体的なタイトルがあがってくると盛り上がってくるなあ,とおもった。


Blogger, BMRT

2001-08-25

今日は休日。なにげに髪を切りに行った。かなり短くしてもらう。すっきり。

ついでに本屋に行って Linux japan 10月号を購入した。この雑誌,その薄さのわりには¥1380って割高な気がするんだけど,たまにはLinux系の雑誌も読んでみようかなあ,ってことで買ってみたのだ。


Linux japan の記事で初めて知ったんだけど,海外ではいわゆるweb日記のことを "Web Log" もしくは短縮して "Blog" って呼ぶんだそうだ。たしかに,Yahoo! で "blog" を検索してみるとしこたまヒットする。

僕は,いままでは,web日記って日本のローカルな流行なのかなあとおもっていたんだけど,どうもそうではなく,世界中でおんなじようなことが行われているみたいだ。ニュース系サイト(TECHSIDEみたいなやつ)なんてもの昔から同じようなのがあったし,国や基盤とする文化は違えど,みんなわりと同じようなことをやってるんだなあ,とおもった。


Linux japan を読んでいて,もうひとつおもしろそうなネタを見つけた。BMRT (Blue Moon Rendering Tool) っていうフリーのCGツールだ。僕はいままで全然知らなかったんだけど,RenderMan互換の高品質レンダラ(しかもフリー)ってことで有名らしい。"Bug's Life" "Hollow Man" などの著名な映画でも使用されたという実績があるんだそうだ。

RednerManってどんなもんなんだろうなあ,とは昔からおもってたんだけど,いかんせん高嶺の花だし,仕事にむりやり絡めるのも難しそうだったんで,わりとあきらめかけてたんだけど,こんな手軽に試せる環境があったとは全然知らなかった。まさに棚からぼた餅って感じ。

んで,さっそくダウンロード。サンプルをレンダリングしてみたり,シーン記述をてきとうにいじってみたりして遊んでみたんだけど,なかなかよさげな感じだ。レイトレーシングによるレンダリングはもちろん,ラジオシティもしくは分散レイトレーシングによるグローバルイルミネーションや,フォトンマッピングを使ったコースティクスなんかもサポートしているらしい。それでいてさらに,RenderMan方式のシーン記述やシェーダースクリプトなんかもサポートしているんで,応用しだいではかなり強力なツールに化けるんじゃないかなあ,とおもった。

http://www.exluna.com/products/bmrt/index.html


パズル

2001-08-26

今日は天気のいい日曜日。天気がいいので洗濯をして,夕方に出勤した。ほんとうは今日中にDMCを終わらそうかとおもってたんだけど,ラストを直前にして,なんとなくこの後の流れも見えてきたし,まあそんなに急ぐこともあるまい,って感じになってきたので,冷静にお仕事に戻ることにしたのだ。

もうちょっとストーリー的なヒキがあればなあ,っておもうんだけど,バイオハザードシリーズっていつもこんな感じなんで,もうしょうがないのかもしれない。


人気のない職場でぽちぽちとお仕事。クオータニオン関連のコードなんかを,いまさらながらいじってみたりした。マルチメディア命令やベクターユニットを使ってならべく速く短いコードを書こうとするんだけど,これはちょっとしたパズルみたいなもんで,なかなか面白い。

特にPS2は,外積演算はあっても内積演算はなかったり,ベクトルの要素の入れ替えが得意じゃなかったりするので,こういったパズルを解くにはちょっとした工夫が必要だ。たとえば,参考書の解説のいちばん最後にのっているような,展開されて短くまとめられた式をそのまま実装すると,かえってステップ数が多くなったりすることがある。その式からちょっとページをさかのぼって,行列や積算がむき出しの状態から実装したほうが速いこともあるのだ。

こういうコードとたわむれるのは,ほんと単純に楽しい瞬間なんだけど,ちょっと不毛な楽しみではあるよな,とおもう。自制しなければいけないのかもしれない。


クオータニオンって

2001-08-27

机の下から起床。職場での起床はなぜか寝起きがいいことが多くて,しょぼい目覚ましの電子音でも跳ね起きるように反応できる(たまにダメなときもあるけど)。環境が違うので眠りが浅いのかなあ,とかおもったんけど,会社で寝るほうが睡眠時間が長いっていう変な生活を送っているので,そうでもないような気もする。

月曜日はミーティングが多いので,仕事はちょっと控えめな感じだ。あったかいコーヒーをすすりながら,昨日書き直したクオータニオンのコードをさっそく利用したりして,ぽちぽちとコードを書き連ねる優雅なひとときをすごしてみた。


ところで,最近は,まれにクオータニオンのお世話になることがあるんだけど,それでもたいていの場合は,クオータニオンは使わずに済むことが多い。

モーションをいじってるひとなんかは事情がぜんぜん違うんだろうけど,ゲームのコアな部分(キャラが歩く……弾が飛ぶ……カメラが動く,など)なんかでは,回転の自由度(degree of freedom : DOF)が狭い場合が多いので,単純な回転方法で済ませられてしまうからだ。

たとえば,地面に立っているキャラなんかはY軸回転量だけ持っていれば十分なことが多いし,カメラについても,実世界のカメラがたいてい2-DOFである以上(ピッチとヨー,あと,がんばればバンクがやっとできる程度),オイラー角で十分だったり,逆にオイラー角の方がいい結果が得られる場合もある。

ところが,たとえば飛行機や誘導ミサイルのように,DOFの広いオブジェクトがでてくると話は違ってくる。オイラー角ではジンバルロックが発生してしまうからだ。


たとえば,ドラゴンの背中にのって飛び回るシューティングゲームを作るとする。ここではまだオイラー角だけで十分そうだ。回転する軸をZ・X・Yの順にしておけば(キャラはZ+を向いているとする)なんとかなりそうな気がする。ここではまだZとXの回転が小さいため,Y回転のDOFが失われる心配がないからだ。

これが,自由に旋回のできる飛行機になったとたん,話は違ってくる。飛行機は真上を向くことができる(X=90度)。この状態から右手の方向に倒れこむ回転は,上で設定した回転順では不可能だ。これがジンバルロックってやつ(僕の解釈にまちがいがなければ……)。

こういう場合は,オブジェクトの回転を表現するのにオイラー角を使うのは無理があるってことになる。


だから,こういう場合は他の方法を使うことになるんだけど,ここでよく使われるのが,回転の組み合わせで姿勢を表現するのはやめて,もっと直接的にローカル座標系を保持してしまおう,って方法。

座標系を作るには3本の直交したベクトルがあればいいんだけど,とりあえず2本用意できればのこりの1本は外積でもとめることができる。上の飛行機の例だったら,前方向と上方向をあらわすベクトルを保持して,そこからローカル座標系をひねりだす,ってのがよさそうだ。

で,これでオブジェクトの姿勢を表現する方法は大丈夫そうなんだけど,こんどは,この姿勢を回転させる方法を探さなきゃいけない。


長くなってきたのでまたいつか……。


クオータニオンって(2)

2001-08-28

で,姿勢を制御する方法なんだけど,僕の場合,任意のベクトルVsをVtに変換するような回転,とか,任意のベクトルVoを軸とする回転,とか,そんなのをよく使う。


VsをVtに変換するような回転,ってやつのほうは,回転の自由度が広いオブジェクトをてきとうに方向転換させるような場合に便利だ。たとえば,誘導ミサイルなんかがこのケースにあてはまる。進行方向さえあっていれば,あとはどんな姿勢になっててもかまわないってのがポイント。

で,VsをVtに変換するんだけど,これは,VsとVtの両方に垂直なベクトルを軸とした回転,と見ることができる。いいかえれば,VsとVtによって作られる平面に垂直な軸を中心とした回転,だ(あんまし変わってないなあ)。この軸はVsとVtの外積から簡単にもとめられる。とりあえずこの軸はVoとしておこう。

次にVsとVoから互いに垂直な軸を作り,ローカルな座標系を構築してみる(正規直交系を作る)。これも簡単で,VsとVoの外積からてきとうに3軸目を作ってしまえばいい。これをVcとする。

Vtについても同様にして,ベクトルVc'を導きだして座標系を作る。こうしてふたつの座標系ができたわけなんだけど,くだんの回転は,この2つの座標系のあいだを変換することに相当する。

そうとなってしまえば,あとは簡単で,ひとつ目の座標系をあらわす行列をMs,ふたつ目の座標系をあらわす行列をMtとするなら,目的の回転に相当する変換行列は

Mr = Mt * Ms^-1

でいいはずだ。雰囲気でいえば,まずは逆行列で標準座標系にもどしてから,次に目的となる座標系に変換する,って感じだ。ちなみにMsは

Ms = | Vs Vo Vc |

で,Mtは

Mt = | Vt Vo Vc' |

でいい。


クオータニオンって(3)

2001-08-29

机の下から起床し,目覚ましがてらにflipcodeをチェックしてみると,doxygenがまたバージョンアップしていた。ん,なんかデジャヴ。とりあえず,あんま変わってなさそうなので,今回もパス。


(きのうの続き)

次に,任意のベクトル Vo を軸とする回転なんだけど,これはVs->Vt変換の応用で実現できる。まず,Vo を [0 0 1](Z軸)に変換するような行列を求めてやって,これを Ma とおく。で,Z軸を中心とする回転を Mz とおくならば,目的とする変換は,

Mr = Ma^-1 * Mz * Ma

であらわされるはずだ。雰囲気でいえば,簡単な回転のできる軸(ここではZ軸)に軸をうつしてから,回転させて,もとの軸に戻している,って感じ。


こうして,数学的なバックグラウンドもへったくれもない無骨な制御方法がいくつか得られたわけなんだけど,こうした方法にはちょっとした問題がある。変換をくり返すことによる演算誤差の問題だ。

まずは,行列の積算自体につきまとう誤差ってのがある。どんなに正確な変換行列が得られたとしても,限られたビット幅(精度)の浮動小数点で演算している以上,演算にはどうしても誤差がともなってくる。この誤差によって,ローカル座標系が正規直交系でなくなってきてしまうのだ。

だから,長時間状態を保持するようなオブジェクトでは,適当な回数の変換をかけるごとに座標系を補正するような処理をかけてやらないと,徐々にオブジェクトの形がゆがんできてしまう。

Gram-Schmidtの直交方法 - http://www.google.co.jp/search?hl=ja&safe=off&q=gram-schmidt&lr=lang_ja


また,行列を求める過程での演算誤差にも気をつかわなければならない。行列を求めるまでに多数の演算があるので,当然ながらここで誤差が発生するし,特にベクトルの正規化では大きな誤差が発生する可能性がある。

ここの方法では,よく外積でもって直交な第3のベクトルを求めているんだけど,外積するときの2ベクトルが平行に近い場合,求まるベクトルはとても小さなものになる(外積の大きさは2ベクトルのなす角の sin に比例する)。このベクトルを正規化するときに大きな誤差が発生するのだ。

この問題は特にVs->Vt変換では避けきれない問題となる可能性がある。1フレーム間に方向ベクトルの変化する量など,たかがしれているからだ。


クオータニオンって(4)

2001-08-30

そんなわけで,オイラー角には操作の幅に限界があるし,行列による表現には誤差や計算量の面でかなりデメリットがある,ということがわかった。

うーん,それじゃあどうしましょうか,ってことになるんだけど,ここで登場するのがクオータニオンだ。クオータニオンによる回転表現ってのは非常に都合よくできていて,これまでの方法でかかえていた問題をほとんど解決することができる。


クオータニオンでまずできることは,任意の回転を表現するってこと。ここらへんの解説を参考書なんかで見てみると,おもわず眠くなっちゃうような説明がえんえんと続いてたりして,ちょっとうんざりするんだけど,まあ結論から言っちゃえば,たとえば4元の同時座標系を使って任意の点を表現するように,クオータニオンを使って任意の回転を表すことができる(きっと,まともな人がこんな例えを見たら怒るだろうな……)。

このとき,クオータニオンを数値的に見ると,任意の軸ベクトルと,その軸まわりの回転量から構成されている(ほんとはもうちょっと複雑だけど)。そんなわけで,任意軸まわりの回転をクオータニオンによる回転表現に変換するのは,ものすごく簡単な作業だ。これは,クオータニオンを使うことのひとつのメリットにもなっている。

次に重要なのが,ふたつのクオータニオン(回転)を合成するには,そのふたつのクオータニオンを乗算してやるだけでいいってこと。クオータニオンどうしの乗算は,外積と内積を組み合わせたみたいな形をしていて,たいていの場合,行列をまともに合成するよりも簡単な処理で実装できる。

そして,任意の回転を表すクオータニオンは,それほど複雑でない計算によって回転行列に変換することができる。だから,実際のプログラムでは,内部的な回転情報としてはクオータニオンで保持しておいて,描画のときなんかに行列として扱いたくなったら,おもむろに行列に変換して使う,ってな感じの使いかたをする。


クオータニオンの応用式のほとんどは,正規化クオータニオンであることを前提としていくらか手抜きをしているので,演算誤差によるずれを補正するために,たまに正規化してやる必要がある。だけどまあ,これは行列の正規直交化なんかとくらべればまったく他愛のない処理なんで,問題になることはないだろう。


他にもクオータニオンにはおもしろい応用方法がいろいろあって,たとえば,まえに書いたVs->Vt変換なんかを誤差の少ない形で実装することができる。これについては,Game Programming Gems の Stan Melax氏の記事に詳しい。


クオータニオンって(5)

2001-08-31

そんなわけで,クオータニオンってのはオブジェクトの回転を表す手段としてよく出来ているし,便利だし,軽いし,スマートでとてもイカすんだけど,さらにおいしいことに,クオータニオンでしかできないことってのもいろいろあったりする。

たとえば,キャラクタアニメーションなんかをいじっている人にとってはかなり重要な要素になるんだけど,クオータニオンは回転の補間を実装するのにも非常にすぐれているということが知られている。


僕や僕のまわりでは,クオータニオンを使う以前は,オイラー角の各要素を線形補間とかでもって回転の補間を実装していたんだけど,この方法には目だった問題がいくつか存在する。

まず問題になるのが,2つのオイラー角の線形補間は,2つの状態を最短の経路で補間することにはならないで,いろんな種類の遠回りな経路をとることがある,ってこと。これは,次に問題にしている「オイラー角の表現は一意ではない」ってとこと少し関連している。

ちょっとおおざっぱな例えになるんだけど,北海道からロンドンに移動する経路を平らな地図の上で考えるのと似ているとおもう。緯度線上にユーラシアを横断して移動する経路や,経度線上に北極を突っ切って移動する経路なんかが考えられるけど,実際に最短になるのはそのどちらでもない。

ちなみに,平らな地図の上でこの最短経路を求めるのはかなり難しいんだけど,地球儀の上で2点間に糸を張れば,簡単に求めることができる。


次に問題になるのが,上でも少し書いたけど,オイラー角とオブジェクトの姿勢は一意に対応しないってこと。たとえば,Y軸回転=0と,Y軸回転=360度は,まったく同じ姿勢を表現しているけど,数値的にはまったく異なっている。単純な数値補間をすると,まったく同じ姿勢を補間しているにもかかわらず,オブジェクトはY軸まわりに1回転してしまうだろう。

アニメーションデータってのは,たいてい,連続的な値として表現される姿勢の変化を離散的にサンプリングしたデータだ。この離散的なデータを滑らかに補間するって目的でオイラー角の補間を使うならば,それほど問題にはならないだろう。もとが連続的な変化なら,いきなり数値がぶっとんだりすることはないだろうし,回転方法の一貫性が保証されているだろうからだ。

ところが,回転の補間ってのは,そのような用途だけではなく,ふたつのまったく関連性がない状態を連続的につなぐって目的にも使われることもある。モーションのクロスフェードなんかがその典型的な例だ。

たとえば,回し蹴りのモーションの後半部を,パンチのモーションの導入部とクロスフェードする場合なんかを考えてみると,単純なオイラー角補間ではうまくいかないことがわかる。姿勢的には同じような「前を向く体勢」なんだけど,オイラー角的には360度ぶっとんでしまっているのだ。そのまま線形補間したら,きっと,ものすごい勢いで逆方向に1回転するだろう。

まあこの例は,正直に数値を補間するんじゃなくて,余計な回転をしないように簡単な補正をかけてやれば済むんだけど,もうちょっと複雑な例で,「X軸回転=180度」と,「Y軸回転=180度 → Z軸回転=180度」が同じ姿勢になる,とかいうケースを考えてみると,ちょっと一筋縄ではいかなくなってしまう。


なんか,だらだら書きすぎのような気もするけど,自分のなかで整理しておきたいところなので,納得するまでだらだら書いてみようとおもう。