SSブログ

ポリゴンレンダラ - その8 [プログラミング]

前回ポリゴンの集合に対して輪郭線を引く方法を考えた。今回の僕の最終的な目的のためには計算が素早くできないといけない。ひとまわりの計算がディスプレイのリフレッシュの間に終わることが望ましい。

ということで、今日は何を計算するかをまとめて、ちょっと実装に先回りして効率のいい計算のためにvDSPを使うことを考えてみる。

vDSPと言えばFFTなんだけど、それ以外の関数もたくさん含まれている。それでどんなことができるのか見通しがよくないので簡単に整理した表を作った。表になにが書いてあるかは続きを読んで欲しい。

6  計算のまとめ

なにを計算するのかをざっくりまとめると
  • 同次座標を使った座標変換
  • 反射光の計算
  • 輪郭線の描画
ということになる。もう少し具体的に書くと
  1. ポリゴンの座標と面の色(とPhong係数)が与えられる
  2. ポリゴンの法線を求めておく
  3. 視点の位置を決める
  4. ポリゴンの座標を平面の上に射影する
  5. 奥行き値によるポリゴンのソートを行う
  6. 光源-ポリゴン-視点の位置関係を調べる
  7. 反射の色を計算する
  8. ポリゴンを描画する
  9. そのとき法線ベクトルと視線ベクトルとの内積を計算し、隣りと符号が逆なら輪郭線を引く
といった計算が必要になるけど、どれも単純なものばかりである。しかしある程度ポリゴンの数が集まらないと形状の直観的な把握も難しいので、大量にしかもはやく処理することが必要になる。

7  計算の効率化

こういう単純な数値計算のために最近のCPUにはベクタユニットが備わっているものが多い。多くのベクタユニットは複数のデータを同時に(たいていの場合1クロックで)処理できる。と言ってもいっぺんに処理できるビット幅はせいぜい128ビット長で、倍精度浮動小数点なら2個ずつしか並列に処理できないのでスパコンのようなものではない。

それに、ベクタユニットを使いたくなるようなアプリケーションはたいていの場合、データがCPUのキャッシュにおさまりきらないぐらい大きい。したがって結局メモリアクセスが律速する、ということになる。

とはいうものの、せっかくあるので使わないのはもったいない。最近のコンパイラはベクタユットも含めて最適するようになっているし、MacOS XにはAccelerateフレームワークがあってベクタユニットに最適化(ものによって、だけど)されている。

また、新しいコンパイラはベクタユニットを使うようなコードも出力できるようになってきている。ヘタにvDSPなんか使ったせいでかえって遅くなる、なんてこともあり得る。

ということで、今回描画の効率を上げたいのでAccelerateフレームワーク、とくにvDSPを試してみる。

vDSPにはいろいろな、というより雑多な関数がごちゃごちゃとある。なかなか全体像がつかめないが、ざっくり言って
  • 配列(1次元、2次元)に対する四則演算やその他の単純演算
  • FFTとそれを使った畳み込みなど
に大別される。今回はこのうちの配列に対する単純演算を使ってみようと思う。

7.1  vDSPの関数

vDSPは呼び出し方が統一されている。例えば二つの配列の要素同士をかけ算する関数のプロトタイプがvDSP programming Guideにある。
void vDSP_vmul(
    float *input_1, /* input vector 1 */
    SInt32 stride_1, /* address stride for input vector 1 */
    float *input_2, /* input vector 2 */
    SInt32 stride_2, /* address stride for input vector 2 */
    float *result, /* output vector */
    SInt32 strideResult, /* address stride for output vector */
    UInt32 size /* real output count */
);
これは単精度浮動小数点数の配列へのポインタを3つわたす。input_1とinput_2という配列にかけ算する数値が並んでいて、その結果がresultという配列に格納されて返ってくる。それぞれの配列の長さは最後の引数のsizeでわたす。入力用の配列は破壊されないが、結果を格納する配列は前もって領域を確保しておく必要がある。ほとんどのvDSP関数は入力を破壊しないが、ほんのいくつかの例外がある。

stride_1とstride_2は二つの配列のストライドを渡す。vDSPの関数があつかう配列は、詰まっている必要は無い。つまり例えば一つおきにならんでいてもいい。いくつ間が空いているかというのをストライドと呼ぶ。ストライドが1というのは密に詰まっている、ストライドが2だと一つおきにある、ということを表している。結果の配列のストライドはstrideResultという引数で渡す。

vDSPではかならず配列は
  • 先頭へのポインタ
  • 長さ
  • ストライド
の3つを指定することになっている。ストライドは配列ごとに違っていていいが、長さは一つ指定すると残りは決まってしまうことが多いので、上の例のように一つだけの場合が多い。

ほとんどの関数は単精度浮動小数点と倍精度浮動小数点に対応する両方の関数が用意されている。そのうちいくつかは複素数用もある。また、ごくたまに32ビット整数用がある。複素数は、必ず実数部と虚数部が別配列になったSplit型複素数にのみ対応する。

vDSPにあるFFT関連はReferenceをみればだいたいわかるが、単純計算の関数は、なにがあってなにがないのかわからないぐらいたくさんある。そこで関数の表(csvファイル)を作った。FFT関連以外の関数を網羅した

表には
  1. タイトル代わりの機能の簡単な説明
  2. 関数名
  3. 配列の型
  4. 機能を式で表現(可能な場合)
  5. 機能の詳細説明
  6. 引数宣言のかたち
を示した。

配列の型は
f: 単精度浮動小数点
D: 倍精度浮動小数点
zf: 単精度浮動小数点複素数
zD: 倍精度浮動小数点複素数
i: 32ビット整数
その他: 1.15固定小数点、8.24固定小数点など特殊なのもの
で示した。

関数名は型による修飾文字がついている。ここに書いた関数名をfuncとすると
vDSP_func 単精度浮動小数点用
vDSP_funD 倍精度浮動小数点用
vDSP_funi 32ビット整数用
vDSP_zfunc 単精度浮動小数点複素数用
vDSP_zfunD 倍精度浮動小数点複素数用
などとなっている。かならず頭にvDSP_がくる。

関数の機能が式で表しやすいものは、LaTeXの形式で式を書いてある。書くまでもないもの(単純コピー関数など)や、式で書きにくいものには書いていない。その場合は機能の詳細説明のところに言葉で書いてある。言葉で書きにくい場合はなんとか式で書くようにして、すくなくともどちらかの説明があるようにしてある。

AppleのvDSP referenceは整理されないまま関数が追加されている(記述がダブってるのもある)ので、見通しが悪い。あらためて分類し直した。わかりやすい分類法があまりないので、若干恣意的に
  • もっとも簡単なもの
    • 単純コピーなど
    • 一つの配列に対して一つのスカラを出力するもの
    • 平均値など
  • 配列の生成
    • 単純代入
    • ランプ関数生成
  • 変換
    • 精度変換
    • デカルト極座標変換
    • デシベル変換
  • 配列の四則演算
    • ベクトルとスカラ
    • ベクトルとベクトル
  • 内積
  • 非線形演算
    • 大小判別
    • 最大値最小値
    • クリピングなど
    • その他
  • ソート
  • 数値積分
  • オートスペクトラム
  • 行列演算
とした。この分類をみても雑多なことがわかるが、個々の関数をみればほんとにいろいろあるということがわかる。でも、なんでもある、というわけではない。何じゃこりゃあ、というのやなにに使うの?なんていうのもある。

vDSPのこういった関数群は、目的があって作られた訳ではなく、どちらかといえばベクタユニットがこういう使い方をすればこういう方面に使えるかもしれない、というシーズ側からの提案になっているせいで雑多なものになっているという気がする。

従って使う方は、目的にあったものを探し出すということができないといけない。そのためにはどんな関数があるのかわかってないといけない。そのためにこういう表はちょっとは役に立つかもしれない、と思って公開することにする。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立04/22献立05/06 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。