パソコン活用研究5番街(Visual Basic、Excel(VBA)、BASIC プログラミング研究)

透視投影図法による3Dグラフィック

(準備中)



============================================================================
3Dグラフィックの始めの一歩として、透視投影図法で立方体を描いてみます。
透視投影図法の説明は今回はかなり簡略化して最低限必要なことだけにとどめます。

============================================================================

1 透視投影図法

3次元の物体を2次元平面上に描く場合、リアルに表現しようとすると遠くの物体は小さく近くの物体は大きく
描きます。つまり遠近法とよばれる描き方です。
遠近法のひとつの方法として透視投影図法があります。

透視投影図法では図1のように、物体から原点(視点)に投影線が収束します。
スクリーン(投影面)に投影された図形が投影図になります。

(図1)


透視投影法の投影面と物体との距離及び投影図の関係について、シンプルな例で説明します。
原点(視点)から距離H離れた投影面と、投影面と平行な線分AB、CDを考えます。
投影面に投影された線分をそれぞれA'B'、C'D'とします。
△OAB∽△OA'B'の関係にあるので、A'B'の線分の長さは=ABの長さ*(H/Z) になります。
同様に、C'D'の長さ=CDの長さ*(H/Z2) となります。
つまり、投影図は視点と物体との距離に反比例して小さくなります。

ABとCDの線分の長さが等しい場合、
A'B' : C'D' = AB*(H/Z) : CD*(H/Z2)
A'B' : C'D' = 1/Z : 1/Z2 = Z2 : Z

もしZ2がZの2倍であれば、C'D'の長さはA'B'の半分になります。
(図2)

点の座標について投影面でどう変換されるかについても、投影面がXY平面と平行という場合に
ついては、
点Aの座標がA(x,y,z)だったとすると、
点A'はA'(x*h/z, y*h/z, h)
ということになります。

2 立方体の透視投影図法


(1)立方体を透視投影図方で描いてみる

話を単純にするために、一辺の長さ100の立方体(正六面体)で手前側の面は
投影面上にあるというシンプルな場合で話を進めます。
視点から投影面の距離は400とします。

簡略な図ですが、図3のようなイメージです。
(図3)

以下はN88互換Basic for Win用のプログラムですが、ほとんどのBasicでもそのまま動作
すると思いますが、それぞれのコンピュータの画面の縦横のアスペクト比を考慮して座標の値は
修正が必要です。
N88互換Basic for Winは表示画面縦横比が1:1なのでシンプルな数値になってます。

初期設定時の手前側(投影面上)の正方形の頂点とその対角の頂点を、x1=0:y1=0:x2=100:y2=100
としています。
正方形のど真ん中の延長線上に視点があると仮定して、奥側の正方形の頂点とその対角にある頂点は
sx1=10:sy1=10:sx2=90:sy2=90
になります。

tx=270:ty=150: stx=270: sty=150 それぞれの正方形の頂点をコンピュータの画面上に表示する時の
座標位置の補正用の変数です。tx,tyが手前側の正方形の描画用。stx,styが奥側の正方形用です。
移動後の表示位置の補正もこの変数で全て行っています。

矢印キーで上下左右に移動させます。
手前の正方形に比べて奥の正方形の移動量は8割になります。
実際の表示は500行目からのサブルーチンです。

<3D.bas>

10 cls
20 x1=0:y1=0:x2=100:y2=100
30 sx1=10:sy1=10:sx2=90:sy2=90
40 tx=270:ty=150: stx=270: sty=150
50 gosub 500
100 a$=inkey$:f=0
110 if a$=chr$(&h1c) and tx<470 then tx=tx+10: stx=stx+8: f=1
120 if a$=chr$(&h1d) and tx>70 then tx=tx-10: stx=stx-8: f=1
130 if a$=chr$(&h1e) and ty>30 then ty=ty-10: sty=sty-8: f=1
140 if a$=chr$(&h1f) and ty<280 then ty=ty+10: sty=sty+8:f=1
150 if a$=" " then end
200 if f=1 then gosub 500
210 goto 100
500 cls
510 line(x1+tx,y1+ty)-(x2+tx,y2+ty),7,B
520 line(sx1+stx, sy1+sty)-(sx2+stx,sy2+sty),5,B
530 line(x1+tx,y1+ty)-(sx1+stx,sy1+sty),7
540 line(x2+tx,y1+ty)-(sx2+stx,sy1+sty),7
550 line(x1+tx,y2+ty)-(sx1+stx,sy2+sty),7
560 line(x2+tx,y2+ty)-(sx2+stx,sy2+sty),7
590 return

(リスト1)

実行中の画像をいくつか掲載しておきます。






(2)外側の面に色を付けてみる

外側になった面に色をつけてみます。
570行目以降で外側の面になったかどうかの判定とpaintで色を塗る処理を追加しました。
手前側の正方形と奥側の正方形の四辺の位置関係を基に、どこを塗るか条件分岐させています。
例えば立方体を右下に移動したときは以下の4個所に色を塗ります。


全部で12個所のパーツに分けて、色を塗るかどうかの判断をしました。
疲れた頭でやっていたので、条件分岐の判定のための式とpaintで色を塗る起点になる座標の指定は、
若干統一性がありませんが、悪しからず。(いつかもう少し整理するかもしれません)

<3D1.bas>

10 cls
20 x1=0:y1=0:x2=100:y2=100
30 sx1=10:sy1=10:sx2=90:sy2=90
40 tx=270:ty=150: stx=270: sty=150
50 gosub 500
100 a$=inkey$:f=0
110 if a$=chr$(&h1c) and tx<470 then tx=tx+10: stx=stx+8: f=1
120 if a$=chr$(&h1d) and tx>70 then tx=tx-10: stx=stx-8: f=1
130 if a$=chr$(&h1e) and ty>30 then ty=ty-10: sty=sty-8: f=1
140 if a$=chr$(&h1f) and ty<280 then ty=ty+10: sty=sty+8:f=1
150 if a$=" " then end
200 if f=1 then gosub 500
210 goto 100
500 cls
510 line(x1+tx,y1+ty)-(x2+tx,y2+ty),7,B
520 line(sx1+stx, sy1+sty)-(sx2+stx,sy2+sty),7,B
530 line(x1+tx,y1+ty)-(sx1+stx,sy1+sty),7
540 line(x2+tx,y1+ty)-(sx2+stx,sy1+sty),7
550 line(x1+tx,y2+ty)-(sx1+stx,sy2+sty),7
560 line(x2+tx,y2+ty)-(sx2+stx,sy2+sty),7
570 if (sx1+stx+1<x1+tx) then paint(x1+tx-1,sy2+sty-30),5,7 ' @
580 if (sx1+stx+1<x1+tx) and (sy1+sty-1 >y1+ty) then paint(x1+tx-1,sy1+sty-1),5,7
590 if (sx1+stx+1<x1+tx) and (sy2+sty+1<y2+ty) then paint(x1+tx-1,sy2+sty+1),5,7 ' B
600 if (x1+tx+1<sx1+stx) and (y1+ty-1>sy1+sty) then paint(sx1+stx-1,y1+ty-1),5,7
610 if y1+ty-1>sy1+sty then paint(sx2+stx-30,y1+ty-1),5,7   ' D
620 if (sx2+stx+1 <x2+tx) and (sy1+sty+1 <y1+ty) then paint (sx2+stx+1,y1+ty-1),5,7 ' E
630 if y2+ty+1 <sy2+sty then paint(sx2+stx-30,sy2+sty-1),3,7
640 if (y2+ty+1<sy2+sty) and (sx1+stx-1>x1+tx) then paint(sx1+stx-1,y2+ty+1),3,7
650 if (y2+ty+1<sy2+sty) and (sx2+stx+1<x2+tx) then paint(sx2+stx+1,y2+ty+1),3,7
660 if x2+tx+1<sx2+stx then paint(x2+tx+1,y1+ty+40),3,7
670 if (x2+tx+1<sx2+stx) and (sy1+sty-1>y1+ty) then paint(x2+tx+1, sy1+sty-1),3,7
680 if (x2+tx+1<sx2+stx) and (sy2+sty+1 <y2+ty) then paint(x2+tx+1,sy2+sty+1),3,7
700 return



実行例



3 座標系

3次元空間に用いられる座標系には、ワールド座標系(右手系)、視点座標系(左手系)があります。

(※)上記「2 立方体透視投影図法」では、コンピュータ画面への表示を簡潔にするため、
それらの座標系とは違いコンピュータの画面(スクリーン)にあわせて、右に行くとx座標値が増え、
下に行くとy座標値が増える座標系でプログラムしています。



(補足) 英語
透視投影法は英語ではperspective projectionといいます。
この単語はどちらも語源を考えると含蓄がありますね。

perspect per=through(通して) + spect=see 〜通して見る =遠近法、見通し

spectを語源に持つ単語
prospect pro(前を) + spect(見る) =見込み、見通し
inspect in(中を) + spect(見る) =検査する
respect re=back(後ろを) + spect(見る) =振り返ってみる ->尊敬する
suspect sus(下) + spect(見る) =下から見る -> 疑う
expect ex(外) + spect(見る) =外を見る ->期待する、予測する
aspect a=to(方を) + spect(見る) =ある方面を見る ->局面

※ sus(下に)は「語源で覚える英単語ple,pli,ply」もご参照下さい。


project pro(前に) + ject=throw(投げる) =投げ出す、計画する、投影する
reject re(後ろに) + ject(投げる) =後ろに投げる ->拒否する
object ob(に向けて) + ject(投げる) = 〜に向けて投げる -> 目標、 反対する
subject sub(下に) + ject(投げる) =下に向けて投げる ->(動詞)服従させる (名詞)学科
inject in(中に) + ject(投げる) =中に投げる ->注入する
eject e=ex(外に) + ject(投げる) =外に投げる ->追い出す


TOP PAGE >Basic活用研究目次