ポリゴン表示に挑む

プチコン4で試作中のポリゴン表示プログラムについて、計算の流れなどを備忘録として残しておきたい

ーーーーーーーーーーーーーーーーーーーーーーーー

<大まかな流れ>

【諸データの格納】
   ↓←LOOP
【造形の回転角・平行移動量の増減】
   ↓
【各頂点の座標を回転・平行移動】
   ↓
【各頂点の空間座標を平面座標へ変換】
   ↓
【各面の重心を計算】
   ↓
【各面の法線を計算】
   ↓
【各法線と光線との角度を計算】
   ↓
【各法線と視線との角度を計算】
   ↓
【各面の表示順序を決定(前後関係)】
   ↓
【各面の発色を決定(ライティング)】
   ↓
【各面の表裏の判定】
   ↓
【各面について、表が視点に向いていれば描画】
   ENDLOOP→

ーーーーーーーーーーーーーーーーーーーーーーーー

【準備するデータ】

MX・MY:画面解像度

LZ:画面~視点までの距離

IX・IY・IZ:視点の座標(IZはLZを代入、IX、IYは0(画面の中心)にする)

B1・B2・B3:光線

PX・PY・PZ:造形の(基準点の)座標

BX[n]・BY[n]・BZ[n]:頂点の回転座標(n:頂点番号)

OBJ[n]・OBJ[n+1]・OBJ[n+2]:面(三角形)の頂点番号(n:面番号)

ー(LOOP)ーーーーーーーーーーーーーーーーー

【造形の回転角・平行移動量の増減】

RAX・RAY・RAZ:各軸における回転角の増減量を更新

PX・PY・PZ:造形の座標を更新

ーーーーーーーー

【頂点座標の回転計算】

|(Xa,Ya)をRAラジアン回転して(X,Y)を得る

|X=Xa×COS(RA)-Ya×SIN(RA)
|Y=Xa×SIN(RA)+Ya×COS(RA)

|上記式を利用して3つの軸について順番に回転していく

<繰り返し:n:0~(頂点の数-1)>

・Y軸回転

FXA=BX[n]×COS(RAY)-BZ[N]×SIN(RAY):中間生成座標(X)
FZA=BX[n]×SIN(RAY)+BZ[N]×COS(RAY):中間生成座標(Z)

・X軸回転

FYA=BY[n]×COS(RAX)-FZA×SIN(RAX):中間生成座標(Y)
BZ[n]=BY[n]×SIN(RAX)+FZA×COS(RAX):Z座標確定

・Z軸回転

BY[n]=FYA×COS(RAZ)-FXA×SIN(RAZ):Y座標確定
BX[n]=FYA×SIN(RAZ)+FXA×COS(RAZ):X座標確定

<繰り返し:ここまで>

※BX,BY,BZは造形の姿勢を表すものに過ぎないので、この変数に平行移動を反映させてはいけない

ーーーーーーーー

【空間座標を平面座標へ変換】

|ここで計算するのは実際に描画されるピクセルの座標

       【ピクセル
       / ||
    【頂点】ー||
    / |  ||
 【視点】ーーーー||←画面
    \    ||

|(底辺):(垂線)として
|(視点~画面):(ピクセル座標)=(視点~頂点):(頂点座標)
|即ち
|(ピクセル座標)=((頂点座標)×(視点~画面))÷(視点~頂点)

|上記式に頂点の平行移動量、画面中央への修正を加味する

<繰り返し:n:0~(頂点の数-1)>

DX[n]=( (BX[n]+PX)×LZ)÷(LZ-(BZ[n]+PZ) )+(MX÷2)
DY[n]=( (BY[n]+PY)×LZ)÷(LZ-(BZ[n]+PZ) )+(MY÷2)

<繰り返し:ここまで>

 ーーーーーーーー

 【面の重心:法線~光線間の角度:法線~視線間の角度を計算】

<繰り返し:n:0~(面の数-1)>

・頂点座標を平行移動量で修正して中間座標(X0~X2,Y0~Y2,Z0~Z2)を生成
各頂点の配列番号は各造形の配列(n×3,n×3+1,n×3+2)が持っている

X0=BX[OBJ[n×3]]+PX:X1=BX[OBJ[n×3+1]]+PX:X2=BX[OBJ[n×3+2]]+PX
Y0=BY[OBJ[n×3]]+PY:Y1=BY[OBJ[n×3+1]]+PY:Y2=BY[OBJ[n×3+2]]+PY
Z0=BZ[OBJ[n×3]]+PZ:Z1=BZ[OBJ[n×3+1]]+PZ:Z2=BZ[OBJ[n×3+2]]+PZ

・面の重心座標を計算 

|重心の位置は、面の表示順序や面への視線を計算する際に使用される

|3点(Xa,Ya,Za)(Xb,Yb,Zb)(Xc,Yc,Zc)の重心(X,Y,Z)は

|X=(Xa+Xb+Xc)÷3
|Y=(Ya+Yb+Yc)÷3
|Z=(Za+Zb+Zc)÷3

重心座標(OX,OY,OZ)は

OX=(X0+X1+X2)÷3
OY=(Y0+Y1+Y2)÷3
OZ=(Z0+Z1+Z2)÷3

この時、OBO[n]にOZ(前後関係の位置)、OBN[n]にn(面の番号)を控えておく

・視線を計算

視線を視点(IX,IY,IZ)~重心(OX,OY,OZ)を結ぶ直線(C1,C2,C3)とするならば
(画面~視点)の距離と(画面~重心)の距離との差、即ち

C1=IX-OX
C2=IY-OY
C3=IZ-OZ

・面の法線を計算

|右回り(Xa,Ya,Za),(Xb,Yb,Zb),(Xc,Yc,Zc)の3点を含む平面の法線(X,Y,Z)は

|X=(Yb-Ya)×(Zc-Za)-(Yc-Ya)×(Zb-Za)
|Y=(Zb-Za)×(Xc-Xa)-(Zc-Za)×(Xb-Xa)
|Z=(Xb-Xa)×(Yc-Ya)-(Xc-Xa)×(Yb-Ya)

平行移動した中間座標から法線(A1,A2,A3)を得る

A1=(Y1-Y0)×(Z2-Z0)-(Y2-Y0)×(Z1-Z0)
A2=(Z1-Z0)×(X2-X0)-(Z2-Z0)×(X1-X0)
A3=(X1-X0)×(Y2-Y0)-(X2-X0)×(Y1-Y0)

・法線と光線、視線との角度を計算

|2直線(Xa,Ya,Za),(Xb,Yb,Zb)間の角度RAは

|COS(RA)=(Xa×Xb+Ya×Yb+Za×Zb)÷
|     (SQR(Xa^2+Ya^2+Za^2)×SQR(Xb^2+Yb^2+Zb^2))

法線(A1,A2,A3)~光線(B1,B2,B3)の角度OBA[n]は

OBA[n]=ACOS( (A1×B1+A2×B2+A3×B3)÷
    (SQR(A1×A1+A2×A2+A3×A3)×SQR(B1×B1+B2×B2+B3×B3)) )

法線(A1,A2,A3)~視線(C1,C2,C3)の角度OBS[n]は

OBS[n]=ACOS( (A1×C1+A2×C2+A3×C3)÷
    (SQR(A1×A1+A2×A2+A3×A3)×SQR(C1×C1+C2×C2+C3×C3)) )

<繰り返し:ここまで>

・面の前後位置(Z座標)を控えたOBO[n]を、面番号を控えた配列OBN[n]
 に連動させてソートし、表示順序を決める

 ーーーーーーーー

【造形を表示する】

各面の前後関係でソートしたOBN[n]の面番号に従って面(三角形)を表示していく

各頂点座標は

(DX[OBJ[OBN[n]×3+(0~2)]],DY[OBJ[OBN[n]×3+(0~2)]])

・ライティング

面の発色(明度)はOBA[n]を元に計算する
(光線が面に対して垂直のときOBA[n]=0で最も明るくなる)

・裏向きの面の判定

OBS[n]が90°(視線と面が平行)を超えた面は裏側を手前(視線側)
に向けている事になる

 ー(ENDLOOP)ーーーーーーーーーーーーーー

以上