3次元CGを学ぶ前に, VisualBasicでの構造体,サブプロシージャ,関数の定義方法等について学んでおく必要がある. 計算量の多い3次元CGを行うためには,これらを利用することがどうしても必要となる.1)構造体(ユーザー定義型)
例えば,以下のようにpoint3dという構造体を定義する.Private Type point3Dプログラム内で,以下のように定義する.
x As Single
y As Single
z As Single
End Type
Dim pnt as point3D
これにより,pntという変数は,pnt.X, pnt.Y, Pnt.Z という1セットの変数を有することができる.
さらに,Dim pnt(100) as point3D
と定義すれば,
pnt(0).X, pnt(0),Y, pnt(0),Z.
pnt(1).X, pnt(1),Y, pnt(1),Z
:.
pnt(99).X, pnt(99),Y, pnt(99),Z.
pnt(100).X, pnt(100),Y, pnt(100),Z.
というように,0から100までの101の配列について,それぞれX,Y,Zを有することが可能である.
2)サブプロシージャの定義
任意のサブプロシージャの定義
例) Test というサブプロシージャを定義する.
Private Sub Test()
Text1.Text = "Testプロシージャが稼動"
End Sub
これを呼び出すには,
Private Sub Command1.Click()
Call Test 'ただしCallは省略可能
End Sub
プロシージャへの引数の受け渡し例)Tashizanという関数を定義する.
Private Sub Tashizan( A As Single, B As Single)
Text1.Text = A + B
End Subこれを呼び出すには,
Private Sub Command2_Click
Tashizan 2.5, 3.8 '引数をもつ場合,Callを付けるとエラーになる.
End SubText1.Textに,計算結果が表示される.
決まりきった手続きを設定する場合に便利な方法である.
3)関数の定義
例)Tashizanf関数を定義する.Private Function Tashizanf(A As Single, B As Single)
Tashizanf=A + B
End Functionこの関数を呼び出すには,
Private Sub Command3_Click
Text1.Text = Tashizanf(2.3, 3.5)
End SubこれでText1.Textに,計算結果が表示される.
4)関数内での変数の定義
引数として型を定義した変数は,あらためて変数として定義する必要はない.
関数あるいはプロシージャ内でのみ使える変数は,関数内において定義すること.
例)
Private Function Tashizanf(A As Single, B As Single) 'A,Bはここで定義される.
Dim Sum As Integer '関数内でのみ利用できる変数として定義
Sum = A + B
Tashizanf = Sum
End Function
基本的に3次元コンピュータグラフィックス(CG)といっても,コンピュータ画面という2次元平面に描画するのであるから,技術的な描画手続きは2次元CGと同様である.その大きな違いは,ベースとなるデータモデルを2次元データとして定義するか,3次元データとして定義するかということである.
人間がスケッチをする場合に,多くの場合において,それは自分の目に映ったものを認識し,それをスケッチブックへと描画している.この過程において,人間は,空間内に位置する3次元の物体を,自分の目を通して2次元に変換し,それをさらにスケーリング(拡大・縮小)を行ない,最終的にスケッチブックに描画しているのである.
また,紙上で機械製図を行なうことを考えてみよう.この場合,設計物は,自分の頭の中に仮想的には3次元物体として存在する.この仮想的な3次元物体を,自分の頭の中で2次元変換して,その変換したものを紙上に図形として描いていく.これらの作業は,すべて人間が,3次元から2次元への変換(3D/2D変換)を行なっているということができる.(実際には,設計者自身がその3次元形状を把握しないまま設計が行なわれるという問題もあるが..)
2次元CGにおける描画も同様である.風景を描画する場合でも,製図を行う場合でも,人間の頭の中での3D/2Dが変換が必要となる.
3次元コンピュータグラフィックスは,このような3D/2D変換をコンピュータで代替えしようというものである.そのために,コンピュータ上では,その元となるデータは3次元形状として構築していく.構築された3次元データをもとに3D/2D変換を行い,コンピュータ画面上に描画すること,これが一般的に3次元CGと呼ばれる技術である.
今回の授業では,実際に,どのように3次元モデルをコンピュータ上に定義するか,またその物体をどのようにして3D/2D変換を行なうかを,VisualBasicのプログラミングを通して学んでいこう.
コンピュータ上で3次元モデルを構築する方法として,以下の方法がある.
1つの直方体を考えてみよう.
直方体は,下図に示すように6つの面から構成されている.ここで面0〜面5として,以下のように定義する.
図-2 直方体の面 直方体を構成する面はすべて四角形であり,それぞれの面は4つの頂点を有している.頂点番号を下図のように定義する(図中( )が頂点番号)
図-3 直方体の頂点 それぞれの面に対して,構成する頂点を整理すると以下のとおりになる.
面0:(0)(1)(2)(3)
面1:(2)(3)(6)(7)
面2:(4)(5)(6)(7)
面3:(0)(1)(4)(5)
面4:(0)(3)(4)(7)
面5:(1)(2)(5)(6)しかし,これらの情報から面を復元することはできない.それは点の順番と面との関係が統一されていないためである.
そこで,面に対する番号付けを,面の表に反時計周りで付けることにしよう.
(ここで面の表が反時計周りであるということが重要である.これは,面の向きを判定する場合の法線計算を行なう際に重要なので,この決まりを守るようにすること.また,CGソフト上でのモデリングでも,基本的にはこの決まりを守るように...)
これらを再整理すると以下のようになる.面0:(0)(1)(2)(3)
面1:(3)(2)(6)(7)
面2:(7)(6)(5)(4)
面3:(0)(4)(5)(1)
面4:(0)(3)(7)(4)
面5:(1)(5)(6)(2)
サーフェースモデルでは,面とそれを構成する点により,その3次元モデルをコンピュータ上に定義する.ここで,それぞれの面をポリゴン(polygon)と呼ぶ.
(問題)
以下のように面0から面3により構成される三角錐がある.これらの面を頂点番号( )により表わしなさい. (当然,三角錐の表面が表である..)
面0:
面1:
面2:
面3:
2.で述べたような3次元モデルの構築を行う場合,図形の頂点を座標,つまり数値で表す必要がある.そのために空間内に3次元座標系を定義する必要がある.
座標系には,右手座標系と左手座標系という2つの種類があり,前者をワールド座標系,後者を視点座標系と呼ぶ場合もある.どちらの座標系を用いるかは,ソフトウェアや適応分野,また場合に応じて異なる.
(重要)
ここでは,OpenGLあるいはVRMLでも採用されている右手座標系を用いる.
z : x = f : u
これを変形すれば,座標uは,
u = f・x /z
となる.
一方,XY座標について考えてみれば,同様に,
z : y = f : v
これを変形して,
v = y * f / z
となる.
すなわち,UV座標系で定義される投影面上において,空間内の点(x,y)の投影点は,
(f・x /z,y
* f / z)
と表される.
Dim pnt(100) As point3D
Private Sub Command1_Click()
Call draw
'コマンドボタンが押されたらdrawを呼び出す.
End Sub
Private Sub Form_Load()
'プログラム起動時に設定する初期値
Form1.ScaleMode = vbTwips
With Picture1
'With...EndWithを用いるとプロパティの設定をブロック化できる.
.Width = 3000
.Height = 3000
.ScaleHeight = -2
.ScaleWidth = 2
.ScaleTop = 1
.ScaleLeft = -1
End With
f = -2
'投影面の位置を-2に設定する.
End Sub
Private Sub draw()
pnt(0) = setPnt(-1, 1.5,
-5)
pnt(1) = setPnt(-1, -1.5,
-5)
pnt(2) = setPnt(1, -1.5,
-5)
pnt(3) = setPnt(1, 1.5,
-5)
pnt(4) = setPnt(-1, 1.5,
-6)
pnt(5) = setPnt(-1, -1.5,
-6)
pnt(6) = setPnt(1, -1.5,
-6)
pnt(7) = setPnt(1, 1.5,
-6)
Quad pnt(0), pnt(1), pnt(2),
pnt(3)
Quad pnt(3), pnt(2), pnt(6),
pnt(7)
Quad pnt(7), pnt(6), pnt(5),
pnt(4)
Quad pnt(0), pnt(4), pnt(5),
pnt(1)
Quad pnt(0), pnt(3), pnt(7),
pnt(4)
Quad pnt(1), pnt(5), pnt(6),
pnt(2)
' Picture1.Line
-(U(pnt(4)), V(pnt(4)))
End Sub
'投影面上のu座標を計算する関数(重要)
Private Function u(p As point3D) As Single
u = p.x * f / p.z
End Function
'投影面上のv座標を計算する関数(重要)
Private Function v(p As point3D) As Single
v = p.y * f / p.z
End Function
'ポイントを構造体に受け渡すための関数(重要)
Private Function setPnt(x As Single, y As
Single, z As Single) As point3D
setPnt.x = x
setPnt.y = y
setPnt.z = z
End Function
'四角形を簡単に描画するためのサブルーチン(重要)
Private Sub Quad(p0 As point3D, p1 As point3D,
p2 As point3D, p3 As point3D)
Picture1.Line (u(p0), v(p0))-(u(p1),
v(p1))
Picture1.Line -(u(p2),
v(p2))
Picture1.Line -(u(p3),
v(p3))
Picture1.Line (u(p3), v(p3))-(u(p0),
v(p0))
End Sub
(演習)
任意の三角錐を定義し,透視投影するプログラムを作成しなさい. ・三角形を描くためのサブルーチンを定義すること. |