素人プログラマーの日常

効率の良いコード、美しいコードなんて書けません。

擬似3D

いやあ、前回の記事から実に1年以上が経過しました。あれからまともにコードを書いてません…汗。ってことで、ちょっと試したいことを久々にプログラミングで表現してみました。

みなさん「平行法」はご存知でしょうか?2つの画像を並べて、右の画像を右目で、左の画像を左目で見ると立体的に見えるという一種の錯視です。これを2Dの画像を使ってリアルタイムで画面上に描画してみたかったんです。あまり形状が複雑なものは計算も複雑になるので相当時間がかかると思います。ですので今回は単純な直方体を描画していきます。

もともと2D画面上でどうやって3Dを表現するか興味があったのですが、今回のようにカメラアングルなどを気にしない簡易的なものであればそれほど難しく考える必要はありません。

まずは遠近法でどのくらいの距離ならどのくらいの大きさで描画すれば良いか考えます。見た目の大きさは距離に反比例するので単純にz値(奥行き=距離)で割るだけです。同じ要領で少し付け加えると画面上の縦と横の位置も求められます。それを直方体の8つの頂点それぞれ算出し、DrawModiGraph関数(画像を自由に変形させる)で1面ずつ描画していきます。

int DrawModiGraph( int x1, int y1, int x2, int y2,
          int x3, int y3, int x4, int y4,
          int GrHandle , int TransFlag );

このとき注意したいのはzソートです。簡単に説明すると、奥にあるものから描画しなければ最終的に画面に出来上がるのはへんてこな画像になるということです。それを考慮したつもりで、直方体の上下左右そして最後に正面を描画しましたが、「???」。左右の面が上下の面を侵食してうまく描画できませんでした。「これって見える角度によって描画順を変えないといけないなあ…」そうなんです。zソートってこんな単純な直方体1個の描画でも問題になるんです。

めんどーなことが嫌いな私はその問題を無視するかのように、見える角度を少しずらして上の面が見えないようにしましたとさ笑。そして左・右・下・正面の順で描画することで事実上問題を回避したと同じ効果を得ました(なんと手ぬるい且つ卑怯な!)。こういったところは私は職業プログラマーに向いてないのかもしれません…。

とはいえ、これで直方体を描画することができました。あとは10個くらい同時に動かしながら右目用と左目用に少し角度を変えて描画していきます。角度といっても三角関数などは使用しません。右目用の画面は手前にくるほど左へ移動し、左目用の画面は手前にくるほど右へ移動するようにずらすだけです。これでお仕舞い。

・・・ではなく、直方体相互のzソートくらいはやっておきましょう。1フレームごとにz値の大小を for文で1回比較するという世にもてきとーなソートですが、奥から手前に真っ直ぐ一定速度で移動するだけなので十分機能します。そのソートした結果を配列に突っ込んで、その配列順に描画していきます。

これで完成です。
↓こんな感じ

f:id:dgen:20161010165816p:plain



にしても、最近の(昔のもそうだけど…)3DCGを見てると「こんなのどうやって作ってるんだ!?(プログラム的に)」と思わざるをえません。単調な擬似3Dでさえ苦戦する私からしたら永遠に手が届きそうにありません。頭良い人っていいね!(なんて横目で羨望の眼差し)

ちなみにコードの掲載は無しです。試作として作ったこともあり、ざっくりと書いているので強引な修正など無駄な部分ばかりで見せるレベルではありません(いつものこと!?)。あしからず。