FC2ブログ
戯言徒然日記開発日記東方DTMC/C++DoJaLuaCG備忘録
気が向いたら創作活動とかしてる人のチラシの裏。
--.--.-- --
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
2008.06.08 Sun
 iアプリに限らずゲーム開発では三角関数を高速に処理したいものです。よく使われる三角関数のテーブル化について書いてみます。
 まず三角関数を求めるメソッドがそもそも遅いのか、ということですが、やはり結構遅いです。特にiアプリなど携帯端末だと速度に大きな影響出す場合もあります。

 これを解決する方法は古典的ですが三角関数をテーブル化するという方法があります。あらかじめ三角関数の値を計算して360°や180°分(あるいはラジアンで)配列に保持しておいて、たとえば、sin(30)などと呼び出した場合は配列のインデックス30番を参照して返す、という具合です。

 たったこれだけですが、iアプリの場合は問題があります。あらかじめ「定数」として配列を持っておく場合、コンパイル後のクラスファイルが大きくなってしまうことです。最近はアプリ容量も大きくなってきたとはいえ、やはりサイズは気になるときが多いです。

 これを解決するには配列の参照だけを定数として持っておくことが有効です。例えば、private static float[] sin_float;というふうに宣言します。そして動的に領域を確保して配列を作成します。

// 360°分配列領域を確保する場合
sin_float = new float[360];

// sin_floatテーブルを作成する
// (ライブラリの三角関数メソッドを使って360°分の値を代入する処理)

 こうすることで.classファイルのサイズをかなり節約することができます。ただ、不便になる点もあります。動的にテーブルを作成することで三角関数メソッドを使う前に必ずテーブル初期化しておく必要があります。これは面倒ですよね;普通三角関数メソッドなどはstaticメソッドにしておいてユーティリティ的に使いたいものです。次はこれを解決しましょう。

 staticな初期化メソッドを作ったりしてもいいのですが、それでは三角関数メソッドがどのような状況で呼び出されても既にテーブルが初期化されていることを保証することはできません。これを行うには初期化処理をstatic初期化子(静的初期化子)で行います。static初期化子はググって他のサイト様を参照すればすぐわかると思いますが、↓みたいなのです。

// 静的初期化
static {
// 三角関数テーブルの初期化処理
}

 静的初期化子はクラスがロードされるときに実行されます。例えば、クラスオブジェクトをnewしてインスタンス化したとき、staticメソッドやstaticフィールドを呼び出したとき、などです。static定数を呼び出しても実行されないので注意してください。

 静的初期化子にテーブルの初期化処理を書いておけば、何の初期化もせず、はじめてLunaMath.sin(270);などと呼び出しても正しく実行することができます。中でははじめてLunaMath.sin(270);を呼び出した際、LunaMathクラスがロードされ、そこでstatic初期化子が実行されます。そしてその後LunaMath.sin(270);が呼び出されています。

 さて、これだけでもかなり使えるのですが、まだ問題はあります。といっても完全な回避できません;それははじめて三角関数メソッドを呼び出したとき、すごい遅くなってしまうことです。上述ですが今のままでははじめてメソッドを呼び出したときに360°分のテーブルを作成するので、低速なライブラリの三角関数メソッドを360回呼び出してから値が返されます。単純計算で360倍遅いですね;

 この問題はどうしても解決は困難です;私はClass.forName( "LunaMath" );(ClassNotFoundExceptionをthrowします。)と明示的にクラスをロードさせることで回避しています。が、これを書かなければいけないならばstaticな初期化メソッドを作成して呼び出すのと大差ないですよね;何かもっとスマートな方法はないものか・・・。

 しかしながら、forNameで明示的なクラスロードを行うことは結構いいと思ってます。PADではDirectXのライブラリ、Lunaを参考にしてエントリーポイントであるstartメソッドを内部に隠蔽しています。つまり、プログラマはゲーム部分のループ処理を書くだけでも動作するようにしています。(こういうことをしているのは毎回毎回忘れたころにstartメソッドを書くのは面倒だったので(笑)PADに関わらず自分で再開発などするときに最小限の労力になるように工夫してみた結果でもあります。)よって、隠蔽されたエントリーポイント部分で明示的なクラスロードを行っているので初期化などを意識しなくても使えるようになっています。

 ここですぐにでも使えるようにソースを貼りたいのですが、今私が持っているソースは元々私が作ったものをベースにつんさんが1/10°単位で三角関数を取得できるように改良したものなので同意なしに公開できません。ということで、最新のものではないですが、そのベースになったものを貼っておきます。参考程度に見てください。

■LunaMath.java

 あらためて見直すと意外と随所に高速化の後がありますね(笑)float->int変換などは今見ると呪文にしか見えない;あ、利用規約などは書いてませんが、PADの規約をきっちり決めてないので、とりあえず今まで通りの扱いで使ってください。なんかあっても知らないのでそこはよろしくお願いします。

[追記]
 Class.forName()を使って明示的な呼び出しをすると実機で落ちるという報告がありました。私の環境およびN904iでは正常に実行できたのですが私としても気になります。なにか情報をお持ちの方がいらっしゃいましたら是非ご教示くださいませ。

[さらに追記]
 float->int変換については山上企画様の読み物コーナーにてわかりやすく説明されています。

 また逆平方根は日々精進時々堕落様のfastNormalizeという記事を参考にした記憶があります。いやほぼそのままJavaに翻訳したような・・・;恐れ入りますm(_ _)m

(リンクに関しての規約は見あたらなかったので無断リンクしています。問題がありましたご一報ください。すぐ対処いたします。)
管理者にだけ表示を許可する

TrackBackURL
→ http://niffy67.blog110.fc2.com/tb.php/127-f97825ec
Template by まるぼろらいと
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。