gombeのブログ

マイコンの電子工作系PIC32/KiCad/C/C++/3D/

マイコンで3Dグラフィクス(1)

マイコンで3D計算というと重すぎるのかと思いましたが以外といけるようなのでそのメモメモ📝

昔のDSとかPS1とかはFPUが付いていないので固定小数点演算でグラフィクスの処理を行いました。現在ではFPUもあるしハードウェアアクセラレータがありますしこんなことしなくてもハードウェアでポリゴンの描画までやってくれますが、やっていることは今も昔も変わりません。

フローを書きましょうね。そうです。だいたいこんな感じです。

オブジェクトの頂点リストをを変形、回転、移動する。それをカメラ行列でカメラの前に持ってきて投射行列を用いて投射する。

投射したら必要に応じて表面の向きの判定をし、面の法線ベクトルから面の輝度計算を行う。頂点リストを整理してy方向でソート後ライン毎に描画をする。

1、投射行列を考える。

A、オブジェクトを考える。

3Dではオブジェクトが置いてあってカメラが設置されてとか色々したいですよね。でも実際一つ一つ行いません。これには訳があって例えば回転ではsin,cosの計算が必要です。膨大な量のデータ一つ一つに対してここに変換しては時間がかかります。ここでは線型性を利用して合成関数をあらかじめ作って最後に変換します。

またこのとき4次元で物事を考えます。並行投影の場合はそこまで大きな恩恵はないのですが(あるけど)透視投影(視点を持った遠近法を適用した投影法)になるとこれが非常に大きな意味を持ちます。まあとにかく4次元です。

3次元だと拡大回転は表現できますが移動などに対して表現ができません。最初はそこで4次元にしたと思ってもらってもいいかな?

物体に対して[回転→拡大→移動]をして欲しい形に欲しい所に移動させたりします。行列では移動させる行列に拡大をかけて、回転をかけます。合成関数の変換なのでこれでおkです。逆にすると大変なことになります。

B、透視投影行列を考える

いよいよ投影座標を考えましょう。投影するためにはカメラもつけたい所ですね。そのためにカメラを移動するのではなく逆にオブジェクトを回転させるようにしましょう。先ほど行った操作と逆なのです逆行列を用意すればいいですね。最後に透視投射行列、これはもういいですね。アスペクト比とかを合わせるのに使います。画面外判定を楽にしたりもできます。投影後に隠面消去を行うためのz成分を求めるのにも使います。

そして頂点データを求め出した行列で変形、透視投射します。最後にw成分で割るのを忘れずに。こうして求め出したベクトル[x,y,z]は、x,yが画面上座標、zはzバッファに用います。

2、陰と明るさを求める

面と光の方向を考慮し、明るさを考えます。並行照明の場合が考えやすいでしょう。太陽を思い浮かべましょう。影は考えません。陰です。降り注ぐ方向と面の法線ベクトルとの内積でその角度を求めて色にかけて簡単に作れます。

‪透視投影が終わったらいよいよポリゴン描画します。私はメモリの都合上スキャンライン法を用いました。ポリゴン数が少ない場合はzバッファ法と大して速度は変わりません。アルゴリズムもほとんど同じで違う点はzバッファのサイズを削減しただけです。削減によってRAMサイズを縮小でき、マイコンの限られた残りのRAMをポリゴン保存やテクスチャなどに活用できます。

スキャンライン法では1ライン分のzバッファのみ保持します。そのためにポリゴン描画も同一ライン上にあるものを全て描画させます。そのためポリゴン描画アルゴリズムレンダリングと同様にスキャンライン法を用いると相性がとても良いでしょう。

長くなったので続きは後で書きます。次はスキャンライン法(多角形描画アルゴリズム)について解説します。

続く