プチコン用 ポリゴン表示プログラム

 これはポリゴンを表示するための命令のないプチコンでポリゴン表示を行うプログラムです。
 DSには3D用チップが搭載されていますが、プチコンからでは利用できないためCPUパワーのみで表示を行っています。プチコンの仕様や性能面やリストの長さの兼ね合いがありますが、下記のようなことができます。


    《 このプログラムでできること 》
     
  • ワイヤーフレームとポリゴンによる表示ができます
    • サンプルデータも4つ用意しているためすぐに使えます
    • データを自分で作る方法も詳細を記載しています
     
  • 光源の位置や強さや色は自由に変えられます
    • 位置はタッチで手軽に変更、強さと色は初期設定値を変えることで対応します
     
  • シェーディングはフラットシェーディングのみ行えます  
  • カメラはオブジェクトに対して正面向きのみとなっています
    • レンズの焦点距離は初期設定値を変えることで変更が可能になります
     
  • オブジェクト単体のX軸、Y軸回転、拡大縮小のみできます
    • タッチ操作で自由自在に拡大縮小や回転操作ができます
グローシェーディングをサポートしない理由は速度面の問題があるだけではなく256色のパレット(本プログラムでは15色x16階調として使用しているため)では厳しいし多くの頂点数を扱えないプチコンでは活かせないし、テクスチャマッピングはGPSETで1ドットずつ行う必要があるため単純に速度面の問題で現実的ではない(大きなポリゴンだと1枚当たりの描画に数秒かかってしまう場合がある)という理由であるためサポートしていません。必要な方は自分で実装してみるのもいいかもしれません。

 いくつか制約はありますが、立方体で17〜20fps程度、24面体で13〜14fps程度の速度となっており、プチコン用プログラムとしては最高速だと思います。またワイヤーフレーム表示時はポリゴン表示とは別の専用のルーチンを使用しているため立方体で122〜123fps程度と高速です。


 《 メニュー 》


《 プログラムリスト 》

ACLS:CLEAR:PNLTYPE "OFF"
V_MAX=999:L_MAX=999:P_MAX=999
DIM VX(V_MAX),VY(V_MAX),VZ(V_MAX)
DIM WX(V_MAX),WY(V_MAX),WZ(V_MAX)
DIM SX(V_MAX),SY(V_MAX)
DIM L1(L_MAX),L2(L_MAX)
DIM P1(P_MAX),P2(P_MAX),P3(P_MAX)
DIM PC(P_MAX),PZ(P_MAX),PN(P_MAX)

GPAGE 1
FOR I=1TO 11
 GLINE I*21.3,0,I*21.3,191,13-(I==6)
 GLINE 0,I*16,255,I*16,13-(I==6)
NEXT

FOR I=0TO 3
 READ C$
 SPPAGE 1
 CHRSET "SPS",I,C$
 SPPAGE 0
 CHRSET "SPU",I,C$
NEXT
FOR I=0TO 1
 SPPAGE !I
 SPSET 0,0,0,0,0,0
 SPHOME 0,8,8
 SPOFS 0,!I*137-9,!I*96
NEXT

@LIGHTING
BG=0:AM=3
RL=255:GL=255:BL=255
GPAGE 0
FOR I=1TO 15
 COLREAD("GRP",I),R0,G0,B0
 FOR J=0TO 15
  R=R0*(AM+15-J)/(AM+16)*RL/255
  G=G0*(AM+15-J)/(AM+16)*GL/255
  B=B0*(AM+15-J)/(AM+16)*BL/255
  C$=HEX$(R,2)+HEX$(G,2)+HEX$(B,2)
  COLSET "GRP",J*16+I,C$
 NEXT
NEXT

@INIT
FL=200:CL=FL
PL=0:PP=0:SH=1:RX=0:RY=0:LZ=1
BGMPLAY RND(23)+7
MD$(0)="CUBE"
MD$(1)="SOLID24"
MD$(2)="TRIFORCE"
MD$(3)="ANDORGENESIS"
IF MD$(MD)>""THEN RESTORE "@"+MD$(MD)ELSE RESTORE "@"+MD$(0)

READ VT
VT=VT-1
FOR I=0TO VT
 READ VX(I),VY(I),VZ(I)
NEXT

READ LN,LC
LN=LN-1
FOR I=0TO LN
 READ L1(I),L2(I)
NEXT

READ PG
PG=PG-1
FOR I=0TO PG
 READ P1(I),P2(I),P3(I),PC(I)
NEXT

@MAIN
GPAGE 0,N,2-N:N=2-N
TC=TCHST:BT=BUTTON()
IF !BT THEN SPOFS 0,-16,0
IF !TC*!BT THEN@VT
PX=TX:PY=TY:TC=TCHST:TX=TCHX:TY=TCHY
BT=BUTTON():TR=BT-(PB AND BT)
IF TR AND 3THEN PL=!(2-(TR AND 2))
IF TR AND 12THEN PP=!(8-(TR AND 8))
IF TR AND 1568THEN SH=!(1024-(TR AND 1024))
IF TR AND 240THEN MD=0OR LOG(TR)*1.45-4:MEM$=STR$(MD):GOTO @INIT
IF !BT*(TX>223)THEN CL=CL+(TY-PY)*TC*PT*FL/200:IF CL IF !BT*(TX<224)THEN RY=(RY+(PX-TX)*TC*PT+360)%360:RX=(RX+(PY-TY)*TC*PT+360)%360
IF BT AND 256THEN GOSUB @LIGHT

' VERTEX ROUTINE
@VT
SN=SIN(RAD(RY))CS=COS(RAD(RY))
SI=SIN(RAD(RX))CO=COS(RAD(RX))
FOR I=0TO VT
 V=CS*VZ(I)-SN*VX(I)
 WX(I)=CS*VX(I)+SN*VZ(I)
 WY(I)=CO*VY(I)-SI*V
 WZ(I)=SI*VY(I)+CO*V
 SX(I)=0OR 128+WX(I)*FL/(CL+WZ(I)*PP)
 SY(I)=0OR 96-WY(I)*FL/(CL+WZ(I)*PP)
NEXT

GCLS BG
ON PL GOSUB@WIRE,@POLY
FPS=FPS+1IF MAINCNTL-CNT>59THEN LOCATE 0,0?"FPS"FPS,:FPS=0CNT=MAINCNTL
PT=TC:PB=BT
GOTO @MAIN

@LIGHT
A=SIN(PI()/256*(128-TX))*TC
LY=SIN(PI()/192*(TY-96))*TC
B=SQR(1-LY*LY)
LX=A*B:LZ=SQR(1-A*A)*B
SPPAGE 1
IF TC THEN UX=TX:UY=TY ELSE UX=128:UY=96
SPOFS 0,UX,UY
SPPAGE 0
SPOFS 0,(144-LX*96)*PL-16,LY*96+96
SPSCALE 0,LZ*100+100
RETURN

' WIRE FRAME DRAW
@WIRE
FOR I=0TO LN
 GLINE SX(L1(I)),SY(L1(I)),SX(L2(I)),SY(L2(I)),LC
NEXT
RETURN

@POLY
' Z SORT
FOR I=0TO PG
 Z(0)=WZ(P1(I))
 Z(1)=WZ(P2(I))
 Z(2)=WZ(P3(I))
 SORT 0,3,Z
 PZ(I)=Z(0)+Z(2)*2
 PN(I)=I
NEXT
RSORT 0,PG+1,PZ,PN

' POLYGON DRAW
FOR K=0TO PG
 B=PN(K)A=P1(B)
 X0=WX(A)Y0=WY(A)Z0=WZ(A)
 X(0)=SX(A)Y(0)=SY(A)
 A=P2(B)
 X1=WX(A)Y1=WY(A)Z1=WZ(A)
 X(1)=SX(A)Y(1)=SY(A)
 A=P3(B)
 X2=WX(A)Y2=WY(A)Z2=WZ(A)
 X(2)=SX(A)Y(2)=SY(A)
 NZ=(X0-X2)*(Y1-Y0)-(Y0-Y2)*(X1-X0)
 IF !PP*(NZ>=0)THEN NEXT:RETURN
 NX=(Y0-Y2)*(Z1-Z0)-(Z0-Z2)*(Y1-Y0)
 NY=(Z0-Z2)*(X1-X0)-(X0-X2)*(Z1-Z0)
 NS=SQR(NX/4096*NX+NY/4096*NY+NZ/4096*NZ)*64
 IF PP THEN VS=SQR(X0*X0+Y0*Y0+(Z0+CL)*(Z0+CL))ELSE VS=1
 IF(NX/NS*X0/VS+NY/NS*Y0/VS)*PP+NZ/NS*(Z0+CL)/VS>=0THEN NEXT:RETURN
 LV=NX/NS*LX+NY/NS*LY+NZ/NS*LZ
 IF LV<-0.99THEN LV=-0.99ELSE IF LV>0THEN LV=0
 C=PC(B)+SH*(0OR 15.9+LV*16)*16
 GOSUB @TRI
NEXT
RETURN

@TRI
SORT 0,3,X,Y:P=X(2)-X(0)
SORT 0,3,Y,X:Q=Y(2)-Y(0)
IF Q>P THEN @T
X=X(0)Y=Y(0)M=Y-Y(2)
Q=(X(0)-X(2))/(M+!M)Z=X
FOR J=0TO 1
 M=Y(J)-Y(J+1)
 P=(X(J)-X(J+1))/(M+!M)
 X=X+(X(1)-X(0))*!M
 A=Y(J)B=Y(J+1)-1
 FOR I=A TO B
  GLINE X,I,Z,I,C
  X=X+P:Z=Z+Q
 NEXT
NEXT
RETURN
@T
SORT 0,3,X,Y
X=X(0)Y=Y(0)M=X-X(2)
Q=(Y(0)-Y(2))/(M+!M)Z=Y
FOR J=0TO 1
 M=X(J)-X(J+1)
 P=(Y(J)-Y(J+1))/(M+!M)
 Y=Y+(Y(1)-Y(0))*!M
 A=X(J)B=X(J+1)-1
 FOR I=A TO B
  GLINE I,Y,I,Z,C
  Y=Y+P:Z=Z+Q
 NEXT
NEXT
RETURN

' SUN CHR DATA
DATA 2000000202000002002000000002002200000200000020000000200200020020
DATA 0000002000000200000020002200000000200000000200002000200002002000
DATA 2202002000020002000020000000020000020022002000000200000220000002
DATA 0020202200202000002020000200200020020000000002000000002000000002

' OBJECT DATA

@SOLID24

' VERTEX DATA
DATA 14
DATA 0,50,0,-10,10,-10
DATA 10,10,-10,10,10,10
DATA -10,10,10,-10,-10,-10
DATA 10,-10,-10,10,-10,10
DATA -10,-10,10,-50,0,0
DATA 0,0,-50,50,0,0
DATA 0,0,50,0,-50,0

' LINE DATA
DATA 36,11
DATA 0,1,0,2,0,3,0,4
DATA 1,2,2,3,3,4,4,1
DATA 5,6,6,7,7,8,8,5
DATA 1,5,2,6,3,7,4,8
DATA 9,1,9,4,9,5,9,8
DATA 10,1,10,2,10,5,10,6
DATA 11,2,11,3,11,6,11,7
DATA 12,3,12,4,12,7,12,8
DATA 13,5,13,6,13,7,13,8

' POLYGON DATA
DATA 24
DATA 0,2,1,2,0,3,2,2
DATA 0,4,3,2,0,1,4,2
DATA 9,4,1,4,9,8,4,4
DATA 9,5,8,4,9,1,5,4
DATA 10,1,2,10,10,2,6,10
DATA 10,6,5,10,10,5,1,10
DATA 11,2,3,5,11,6,2,5
DATA 11,7,6,5,11,3,7,5
DATA 12,3,4,12,12,7,3,12
DATA 12,8,7,12,12,4,8,12
DATA 13,5,6,15,13,6,7,15
DATA 13,7,8,15,13,8,5,15

@CUBE

' VERTEX DATA
DATA 8
DATA -32,-32,-32,-32,32,-32
DATA 32,-32,-32,32,32,-32
DATA -32,-32,32,-32,32,32
DATA 32,-32,32,32,32,32

' LINE DATA
DATA 12,15
DATA 0,1,1,3,2,3,2,0,0,4,1,5
DATA 2,6,3,7,4,5,5,7,6,7,6,4

' POLYGON DATA
DATA 12
DATA 0,1,2,15,1,3,2,15
DATA 2,3,6,15,6,3,7,15
DATA 0,6,4,15,0,2,6,15
DATA 0,4,5,15,0,5,1,15
DATA 1,5,7,15,1,7,3,15
DATA 4,6,5,15,5,6,7,15

@TRIFORCE

' VERTEX DATA
DATA 12
DATA 0,60,0,-23.1,20,0
DATA 23.1,20,0,-46.2,-20,0
DATA 0,-20,0,46,-20,0
DATA 0,60,10,-23.1,20,10
DATA 23.1,20,10,-46.2,-20,10
DATA 0,-20,10,46.2,-20,10

' LINE DATA
DATA 24,12
DATA 0,1,1,2,2,0,1,3,3,4,4,1
DATA 2,4,4,5,5,2,6,7,7,8,8,6
DATA 7,9,9,10,10,7,8,10,10,11,11,8
DATA 0,6,1,7,2,8,3,9,4,10,5,11

' POLYGON DATA
DATA 18
DATA 0,2,1,12,1,4,3,12
DATA 2,5,4,12,6,7,8,12
DATA 7,9,10,12,8,10,11,12
DATA 0,11,5,8,11,0,6,8
DATA 0,9,6,8,9,0,3,8
DATA 3,11,9,8,11,3,5,8
DATA 1,8,7,7,8,1,2,7
DATA 1,10,4,7,10,1,7,7
DATA 2,10,8,7,10,2,4,7

@ANDORGENESIS

' VERTEX DATA
DATA 98
DATA 0,0,-20,-30,72,0
DATA 30,72,0,72,30,0
DATA 72,-30,0,30,-72,0
DATA -30,-72,0,-72,-30,0
DATA -72,30,0,-12,29,-15
DATA 12,29,-15,29,12,-15
DATA 29,-12,-15,12,-29,-15
DATA -12,-29,-15,-29,-12,-15
DATA -29,12,-15,-15,72,0
DATA 15,72,0,72,15,0
DATA 72,-15,0,15,-72,0
DATA -15,-72,0,-72,-15,0
DATA -72,15,0,-6,29,-15
DATA 6,29,-15,29,6,-15
DATA 29,-6,-15,6,-29,-15
DATA -6,-29,-15,-29,-6,-15
DATA -29,6,-15,-15,26,-15
DATA 15,26,-15,26,15,-15
DATA 26,-15,-15,15,-26,-15
DATA -15,-26,-15,-26,-15,-15
DATA -26,15,-15,40,51,-3
DATA 51,40,-3,51,-40,-3
DATA 40,-51,-3,-40,-51,-3
DATA -51,-40,-3,-51,40,-3
DATA -40,51,-3,20,29,-14
DATA 27,36,-11,36,27,-11
DATA 29,20,-14,29,-20,-14
DATA 36,-27,-11,27,-36,-11
DATA 20,-29,-14,-20,-29,-14
DATA -27,-36,-11,-36,-27,-11
DATA -29,-20,-14,-29,20,-14
DATA -36,27,-11,-27,36,-11
DATA -20,29,-14,-4,33,-10
DATA 4,33,-10,33,4,-10
DATA 33,-4,-10,4,-33,-10
DATA -4,-33,-10,-33,-4,-10
DATA -33,4,-10,-15,26,-10
DATA 15,26,-10,26,15,-10
DATA 26,-15,-10,15,-26,-10
DATA -15,-26,-10,-26,-15,-10
DATA -26,15,-10,-5,12,-16
DATA 5,12,-16,12,5,-16
DATA 12,-5,-16,5,-12,-16
DATA -5,-12,-16,-12,-5,-16
DATA -12,5,-16,-30,72,10
DATA 30,72,10,72,30,10
DATA 72,-30,10,30,-72,10
DATA -30,-72,10,-72,-30,10
DATA -72,30,10,0,0,10

' LINE DATA
DATA 128,10
DATA 1,2,2,3,3,4,4,5
DATA 5,6,6,7,7,8,8,1
DATA 9,10,10,11,11,12,12,13
DATA 13,14,14,15,15,16,16,9
DATA 1,33,2,34,3,35,4,36
DATA 5,37,6,38,7,39,8,40
DATA 17,25,18,26,19,27,20,28
DATA 21,29,22,30,23,31,24,32
DATA 34,41,41,42,42,35,36,43
DATA 43,44,44,37,38,45,45,46
DATA 46,39,40,47,47,48,48,33
DATA 49,50,50,51,51,52,52,49
DATA 53,54,54,55,55,56,56,53
DATA 57,58,58,59,59,60,60,57
DATA 61,62,62,63,63,64,64,61
DATA 17,65,65,66,66,18,25,65
DATA 26,66,19,67,67,68,68,20
DATA 27,67,28,68,21,69,69,70
DATA 70,22,29,69,30,70,23,71
DATA 71,72,72,24,31,71,32,72
DATA 1,73,48,73,33,73,2,74
DATA 41,74,34,74,3,75,42,75
DATA 35,75,4,76,43,76,36,76
DATA 5,77,44,77,37,77,6,78
DATA 45,78,38,78,7,79,46,79
DATA 39,79,8,80,47,80,40,80
DATA 81,82,82,83,83,84,84,85
DATA 85,86,86,87,87,88,88,81
DATA 89,90,90,91,91,92,92,93
DATA 93,94,94,95,95,96,96,89
DATA 1,89,2,90,3,91,4,92
DATA 5,93,6,94,7,95,8,96

' POLYGON DATA
DATA 152
DATA 9,10,81,13,10,82,81,13
DATA 10,11,82,13,11,83,82,13
DATA 11,12,83,13,12,84,83,13
DATA 12,13,84,13,13,85,84,13
DATA 13,14,85,13,14,86,85,13
DATA 14,15,86,13,15,87,86,13
DATA 15,16,87,13,16,88,87,13
DATA 16,9,88,13,9,81,88,13
DATA 1,17,9,13,17,25,9,13
DATA 17,18,65,13,18,66,65,13
DATA 18,2,26,13,2,10,26,13
DATA 2,3,74,13,3,75,74,13
DATA 3,19,11,13,19,27,11,13
DATA 19,20,67,13,20,68,67,13
DATA 20,4,28,13,4,12,28,13
DATA 4,5,76,13,5,77,76,13
DATA 5,21,13,13,21,29,13,13
DATA 21,22,69,13,22,70,69,13
DATA 22,6,30,13,6,14,30,13
DATA 6,7,78,13,7,79,78,13
DATA 7,23,15,13,23,31,15,13
DATA 23,24,71,13,24,72,71,13
DATA 24,8,32,13,8,16,32,13
DATA 8,1,80,13,1,73,80,13
DATA 1,89,2,13,89,90,2,13
DATA 2,90,3,13,90,91,3,13
DATA 3,91,4,13,91,92,4,13
DATA 4,92,5,13,92,93,5,13
DATA 5,93,6,13,93,94,6,13
DATA 6,94,7,13,94,95,7,13
DATA 7,95,8,13,95,96,8,13
DATA 8,96,1,13,96,89,1,13
DATA 34,41,49,13,41,50,49,13
DATA 41,42,50,13,42,51,50,13
DATA 42,35,51,13,35,52,51,13
DATA 49,52,34,13,52,35,34,13
DATA 36,43,53,13,43,54,53,13
DATA 43,44,54,13,44,55,54,13
DATA 44,37,55,13,37,56,55,13
DATA 53,56,36,13,56,37,36,13
DATA 38,45,57,13,45,58,57,13
DATA 45,46,58,13,46,59,58,13
DATA 46,39,59,13,39,60,59,13
DATA 57,60,38,13,60,39,38,13
DATA 40,47,61,13,47,62,61,13
DATA 47,48,62,13,48,63,62,13
DATA 48,33,63,13,33,64,63,13
DATA 61,64,40,13,64,33,40,13
DATA 17,65,25,13,65,66,25,13
DATA 66,26,25,13,18,26,66,13
DATA 19,67,27,13,67,68,27,13
DATA 68,28,27,13,20,28,68,13
DATA 21,69,29,13,69,70,29,13
DATA 70,39,29,13,22,30,70,13
DATA 23,71,31,13,71,72,31,13
DATA 72,32,31,13,24,32,72,13
DATA 2,74,34,13,2,34,10,13
DATA 3,35,75,13,3,11,35,13
DATA 4,76,36,13,4,36,12,13
DATA 5,37,77,13,5,13,37,13
DATA 6,78,38,13,6,38,14,13
DATA 7,39,79,13,7,15,39,13
DATA 8,80,40,13,8,40,16,13
DATA 1,33,73,13,1,9,32,13
DATA 50,51,49,2,51,52,49,2
DATA 54,55,53,2,55,56,53,2
DATA 58,59,57,2,59,60,57,2
DATA 62,63,61,2,63,64,61,2
DATA 81,82,0,2,82,83,0,2
DATA 83,84,0,2,84,85,0,2
DATA 85,86,0,2,86,87,0,2
DATA 87,88,0,2,88,81,0,2
DATA 89,97,90,1,90,97,91,1
DATA 91,97,92,1,92,97,93,1
DATA 93,97,94,1,94,97,95,1
DATA 95,97,96,1,96,97,89,1
QRコード(ファイル名:OCHAPOLY)


《 使用方法 》

 ポリゴン表示するためにはまずはデータを作成する必要がありますが、データの作り方は後述に記載しています。まずは、このプログラムには4つのサンプルデータが用意されているためそれを使って表示していきます。

 まず、RUNで実行してください。立方体(というか四角形)が表示されたと思います。そして、上画面の左上には概算のFPS(1秒間の表示回数)が表示されています。
 下画面を見てみると格子状の線に加えて中央に赤い太陽のようなマークが表示されていると思います。下画面は光源の位置を示すものでこれは具体的には後で説明しますのでまずはメインとなる上画面の方から見ていきます。

 サンプルデータとして立方体、24面体、トライフォースのようなもの、アンドアジェネシスのようなものの4つが用意されていて、それぞれ[A][B][X]{Y]ボタンに割り当てられています。デフォではワイヤーフレーム表示となっていますが、十字ボタンの下でポリゴンと切り替えることができます。左右でパースのON、OFFが設定できます。パースONはカメラから見た目通りの表示となっていますが、広角レンズであるため遠近感が強調された状態となります。デフォではパースはOFFになっており遠近感が付かないためオブジェクトの形を正確に把握するのに適した状態となっています。(下記の設定変更で焦点距離を大きくして望遠レンズにすれば遠近感が少なくなり望遠レンズによる圧縮効果が体感できるけどパースOFFとの差別化もあまりできなくなるため標準では広角レンズとしている)
 また[START]ボタン、[R]ボタンでシェーディングのONとOFFができます。シェーディングは光が当たってない部分を暗くする処理ですが、デフォでは光源はカメラのある方向にと同じという設定にしているため真っ正面に見える面(視線に対して垂直な面)が最も明るくなります。なお、このシェーディングの設定はポリゴン表示のみ有効でワイヤーフレーム表示時はONにしておいても無視されます。

 タッチパネルで回転や拡大・縮小ができます。ボタンを押してない状態でタッチパネルの左右方向にスライドさせると左右方向に回転(Y軸回転)を行い、上下方向にスライドさせると上下回転(X軸回転)を行います。この縦回転、横回転というのはあくまでX軸回転、Y軸回転なのでオブジェクトが上下逆表示の時には回転方向は左右が逆になります。
 また画面右端を上下方向にスライドさせると拡大、縮小ができます。なおこの拡大、縮小はカメラ位置を近づけたり遠ざけたりすることで行っているためパースONの状態だと遠近感にも変化が出てきます。端的に言えば、回転は普通のマウスのような操作、拡大縮小はマウスホイールのような操作と考えれば分かりやすいと思います。

 タッチパネルと[L]ボタンとを併用することで光源の方向を指定することができます。ポリゴン表示時に[L]ボタンを押すと上画面に太陽マーク(光源の方向)が画面に表示されます。これはその場所に光源があるというのではなく平行光源なのでその太陽マークがある方向の無限遠に光源はあります。
 太陽マークはタッチする座標を元に移動します。画面中央がオブジェクトの正面で画面の上下左右をタッチすることでオブジェクトの上下左右の自由な位置に移動することができます。下画面の格子状の線は世界地図をイメージしてもらえると分かりやすいです。黄色い線は緯度経度が0度の位置でその中央がオブジェクトの正面向きとなります。線1本の間隔は15度単位になっています。画面中央から数えて右に2目盛り、上に3目盛りの位置に太陽マークを置いたら(ユーザーから見て)右に30度、仰角45度の方向に光源があるということを示しています。
 [L]ボタンを押しながらタッチすると下画面の太陽マークが動かせるのでオブジェクトの周囲を球面で覆ったと仮定して縦横の座標のみで三次元座標を指定することが可能になっています。地球儀で考えれば分かりやすいですが、下画面の上端はすべて同じ座標(北極)を示し、下画面の下端もすべて同じ座標(南極)を示すわけです。(十分なfpsがあればタッチしたままペンを動かすとスムーズに太陽マークが移動する)
 また、[L]ボタンを単独に押せば光源の方向は初期化(正面向き)されます。。したがって、タッチで決めた光源の位置を固定するためにはタッチしている状態で[L]ボタンを先に離してください。操作は変則的ですが、慣れたら感覚的に操作でき非常に分かりやすいと思います。
 
 あと、このプログラムでは初期値を変えることでレンズの焦点距離や光源の設定なども設定変更が可能になっています。
 LIST @INITとしてください。最初に設定するのがオブジェクトの中心からのカメラの距離とそのカメラに使用しているレンズの焦点距離です。焦点距離は、変数FLの値を変更することで変えることができます。デフォではFL=200となっていますが、これは水平画角64度の広角レンズ(概ね水平画角60度以上が広角レンズ、30〜60度が標準レンズ、30度以下が望遠レンズ)となっています。水平画角はDEG(ATAN(128/FL))*2で求めることが可能です。またFLの値を7.1で割れば35mmカメラ換算の焦点距離となります。FL=200の場合だと200÷7.1≒換算28mm相当のレンズとなるわけです。

 カメラ距離に関してはこのプログラムの場合はレンズの焦点距離を変えてもオブジェクトが画面上で大体同じくらいの大きさになるように自動的に変えてくれるため特に弄る必要はないです。変える場合は変数CLの値を変更してください。レンズの焦点距離によって最短撮影距離CLの最小値はFLの半分の値)を設定しているためその部分の変更が必要になる場合もあります。(単純に大きくしたいならばスクリーン座標へ変換する式をX、Y座標ともに2倍とか3倍とかになるようにしたトリミング表示にすればいい)
 あと、カメラの最短撮影距離はオブジェクトの中心からの距離からの距離を元にしているためあまり超広角設定にするとパースONで近接時にカメラがオブジェクトを貫通してしまう(パースOFFだと問題ない)のでプログラムを改造しない限りはレンズの焦点距離は頂点データに使用している値の絶対値の2倍を超えるような値に設定してください。(ちなみに使用している頂点データで最も大きいのはアンドアジェネシスの72であるためレンズの焦点距離の最小値は150程度を目処にするといい)

 次に設定するのが光源です。LIST @LIGHTINGとしてください。光源はメインの光源の色と環境光の強さの設定を行います。デフォではRL=255GL=255BL=255(=白)となっていますが、これをRL=255GL=0BL=0とすれば赤色の光源となります。
 そして、環境光の強さの設定を行います。環境光とは物体に360度当たっている光のことで簡単に言えばメイン光源が全く当たっていない陰の部分の明るさを設定するわけです。これは変数AMの値を変えることで変更ができます。AM=0ならばメイン光源以外は0の強さとなり、光が当たってない部分は真っ黒となります。AM=16ならばメイン光源の半分の強さとなり、AM=32ならば2/3の強さになり、要するにAMに設定している値を大きくすればするほど明暗差が小さくなるということです。デフォではAM=3となっていますが、特に意図がない限りは16階調を有効活用できるためにもAMの値は0〜16くらいの範囲内で設定すると良いでしょう。COLSETではRGB256階調で設定できるけど表示の段階でR、Bは32階調、Gは64階調に丸められてしまうためAMの値が16以下だと丸められた状態でも16階調で表示可能になる)
 あと変数BGの値を変えれば背景色が変わります。0255の範囲で設定できます。BG=0は常に黒(厳密には透明色)ですが115までの15色は光源の色の影響を受けます。また16255は階調用のパレットなので環境光設定の影響も受けます。

《 操作一覧表 》
[A]ボタン
サンプルデータ1 立方体
[B]ボタン
サンプルデータ2 24面体
[X]ボタン
サンプルデータ3 トライフォースのようなもの
[Y]ボタン
サンプルデータ4 アンドアジェネシスのようなもの
[R]ボタン
シェーディング OFFで表示
[START]ボタン
シェーディング ONで表示
[↑]ボタン
ワイヤーフレームで表示
[↓]ボタン
ポリゴンで表示
[←]ボタン
パース OFFで表示
[→]ボタン
パース ONで表示
タッチパネル
(ボタンを押さず)上下左右にスライド
上下左右に回転
タッチパネル
(ボタンを押さず)右端を上下にスライド
拡大・縮小
[L]ボタン
光源の方向を初期化(正面向きに戻す)
[L]ボタンを押した状態で画面タッチ
光源をオブジェクトに対して上下左右に移動
※デフォではワイヤーフレーム表示、パースOFF、シェーディングONとなっています。
 ONとOFFをトグル切り替えにしなかったのは、ステータス表示無しで画面をすっきりさせたかったためです。

《 データの作り方 》

 データは、頂点データ、ワイヤーフレーム用のインデックスデータ、ポリゴン用のインデックスデータが必要です。
 頂点データは上がY座標のプラス、奥行き方向がZ座標のプラスになるような座標系(要するにDirect3Dと同じ左手座標系)における値を入れていきます。回転の中心を原点(0,0,0)にしておけばその座標を中心に回転します。(このプログラムではデータ上の原点は画面上のほぼ中心となる(128,96)の座標に表示される)
 問題は入れる値の大きさですが、サイズはプログラムを改造することで自由に変えられるため特に気にする必要はないですがプチコンは小数では1/4096単位で正確に表せる数以外は誤差が発生するため可能な限りは整数値で指定する方が良いでしょう。このプログラムをデフォの状態で使用するならばその指定した値のサイズで表示されます。つまり、データ上でサイズが50のオブジェクトは画面上で50ドットで表示されるということです(パースOFFの場合)。最短撮影距離ならばその2倍の100ドットで表示されます。画面の縦のドット数は192ドットなのでオブジェクトの最大座標を±48程度の大きさにしておけばこのプログラムを使用時には最短撮影距離で画面一杯にそのモデルを表示できます。(拡大率はプログラムを改造すれば自由に変えられるためこのプログラムでは分かりやすさを重視している)

 では、データが具体的にどのような仕組みになっているのか見てみましょう。まず簡単なのはデフォで[A]ボタンに登録されている立方体です。立方体は頂点数が8個なので8個のデータを入力する必要があります。
 立方体のデータを見るにはLIST @CUBEとします。VERTEX DATAのところを見ると最初に頂点数を示す8というデータがあります。次にあるのはその8つの頂点データですが、ここでは(-32,-32,-32)、(-32,32,-32)、(32,-32,-32)、(32,32,-32)、(-32,-32,32)、(-32,32,32)、(32,-32,32)、(32,32,32)としています。先ほどは±48程度ならば画面一杯に表示できると書いていて±32にしているのは回転したときの対角線の長さで考えると√2倍になるためです。±32ならば概ね画面に収まるレベルで最大サイズというわけです。  これが立方体のような単純なものならば頂点データも簡単に求まるのですが、もっと複雑なものも用意したいという人は何らかの方法で計算してください。ちなみに私は今回のサンプルに含まれる4つのデータはすべて脳内で暗算で座標を求めました。このレベルならばそれほど難しくはないのですが、それより複雑になると脳内でのデータ生成には限界があるためモデリングプログラムを作るというのも1つの解決策となるでしょう。(といっても、アンドアジェネシスは暗算では少し無理があったみたいでポリゴンに隙間ができてしまった)

 次にワイヤーフレーム用のインデックスデータです。ワイヤーフレームはポリゴン用とは別に専用のデータを用意することで処理速度やデータの効率化を高めています。すべての頂点を結ぶのではなく一般的な立方体のように辺のみを線で表すならばワイヤーフレーム用に必要な線の数は12本となります。このプログラムにおいてはワイヤーフレームはすべて同じ色の線で描画されるので線の色も最初に決めておきます。白ならばGCOLOR 15であるためLINE DATAの最初のデータは1215になっています。CGCLOR 16以降は階調表現用に使用するため使用できる色は1〜15の15色のいずれかです。この中に使いたい色がない場合は光源設定用のパレット作成前にCOLSETで使いたい色をあらかじめ設定しておいてください。
 あとは、どの頂点と頂点を結ぶかというデータを用意しておけば良いです。先ほどの頂点データの最初から番号を0から順に振り分けているため8つの頂点データは番号0〜7になります。座標からこの立方体の辺となるものは0と1、1と3、2と3、2と0、0と4、1と5、2と6、3と7、4と5、5と7、6と7、6と4を結んだ場合なのでそれをデータとして羅列するだけです。データの順番そのものは特に気にする必要はありません。(例えば頂点1と頂点2を結ぶ場合にはデータを1,2にしても2,1にしてもどちらでも構わない)

 いよいよポリゴン用のインデックスデータです。このプログラムではポリゴンは三角形を単位として描画されますので描画する面を三角形に分割して考える必要があります。立方体の面の数は6であり、1つの面は四角形で構成されています。四角形は2つの三角形を組み合わせて表現可能であるため立方体の1つの面あたり三角形を2つ使うので6面×2=12でポリゴンデータ数は12になります。したがって、POLYGON DATAでは最初に12を入れています。
 そして、インデックスデータを羅列していきます。先ほどは線だったので始点と終点の2つ単位だったのですが、今回は三角形なのでその3つの頂点の番号を並べます頂点番号0、番号1、番号2を結んだ三角形だと0,2,1にすれば良いのです。それにその三角形の色を1つずつ指定することになります。色が白ならば0,2,1,15となります。このプログラムではこのように4つのデータを基本単位として並べていきます。
 この4つのデータを三角形の数である12個羅列すればいいのですが、ポリゴンの場合は裏と表があるためそれを明確にする必要があります。このプログラムでは三角形を表から見て時計回りになるような順番で結んでいきます。これを逆にすると裏側と認識されて画面上には表示されないため注意が必要です。(頂点データによっても異なるけどこのプログラムの立方体のデータの場合は0,2,1ではなく0,1,2とすれば表から見ると反時計回りになっているので表から見た際には描画されず、そのまま後ろが素通しになる)
 1つの三角形は当然3つの辺で構成されているためワイヤーフレーム表示用にこのポリゴンデータを流用すれば3×12で36本の線を描画する必要があります。上記のワイヤーフレーム用のデータだと12本で済んでいるということを考えると単純計算で描画処理が3倍速くなっておりワイヤーフレーム用にデータを分けている理由が分かると思います。(ポリゴン、もしくは、ワイヤーフレームのみ使いたいという人で使わない方のデータまでわざわざ作るのが面倒という場合は使わない方のデータ数を1にしてそこにインデックスデータは0,0,0,0のようなダミーデータを入れれば問題ない)

《 さらに初心者向けの データ作成例 》
頂点(0,0,0)(-50,50,0)(50,50,0)を3点に持つ青い三角形を表示する

@TRIANGLE 他で使用していないラベルを付ける
' VERTEX DATA 頂点データを示す注釈(無くても可)
DATA 3 頂点データ数が3個であるということを示すデータ
DATA 0,0,0,0,-50,50,50,50,0 頂点データのX、Y、Z座標をそれぞれ入力
' LINE DATA ワイヤー(線)データを示す注釈(無くても可)
DATA 3,4 線の数が3本、線の色が青色であるということを示すデータ
DATA 0,1,1,2,2,0 頂点0と1、頂点1と2、頂点2と0を繋ぐということを示すデータ
' POLYGON DATA ポリゴン(三角形)データを示す注釈(無くても可)
DATA 1 三角形の数が1つということを示すデータ
DATA 0,1,2,4 頂点0と1と2を繋いで青色で塗りつぶした三角形ということを示すデータ

 あとはこれでラベル@TRIANGLE[A][B][X][Y]いずれかのボタンに登録すれば良いです。LIST @INITとして初期設定部分のリストを呼び出し、[A]ボタンに登録する場合はすでに登録されているCUBETRIANGLEに書き換えます。ペラペラの1枚の三角形ですが、自由に回転させることができるというのとこのプログラムにおいてポリゴンの裏側は見えないということが分かると思います。
 裏側を描画したければ裏面を示す逆回りのデータを別のポリゴンとして追加すれば良いです。ポリゴン数を示すデータを1から2に変えてポリゴンデータを0,1,2,4から0,1,2,4,0,2,1,10に変えれば表が青色で裏が緑色の三角形になります。見えない側は描画しないのでポリゴン数を増やしても描画が遅くなることはありません。
 こうやってたくさんの三角形を組み合わせて1つのオブジェクトを構成していきます。

《 プログラムの仕組み 》

 簡単な仕組みを書いていくことにしましょう。
 配列変数VX()VY()VZ()に入っている頂点データはそのモデルの中心を原点としたローカル座標で記述されています。それを回転移動させてワールド座標に変換する必要があります。回転は行列式を使うことで出来ます。

 X軸の回転角度をRx、Y軸の回転角度をRyとした場合には行列式を計算すると次のようになります。

  X軸回転 x'=x y'=y cos Rx - z sin Rx z'=y sin Rx + z cos Rx
  Y軸回転 x'=x cos Ry + z sin Ry y'=y z'=-x sin Rx + z cos Ry

 このプログラムでは上記の式を最適化したものを使用することで高速化を図っています。
 回転が終わったら平行移動するだけですが、原点を中心に回転させるだけのプログラムなので回転が終わった座標がワールド座標となります。次にカメラ基準のビュー座標変換を行う必要がありますが、カメラは常にZ軸上にある(Z軸に対して平行な視点となっている)ため次のスクリーン座標への変換でまとめて行っています。もしも、カメラアングルを変える場合にはここでさらに回転移動が必要になってきます。
 最後に行う座標変換がスクリーン座標(画面上の座標)への変換です。このプログラムでは常にカメラがZ軸上にあるためカメラ視点への座標変換(回転移動)は不要で、スクリーン座標への変換だけですがそれはこのように単純な1次式で表すことができます。ここでオブジェクトの各頂点とカメラの距離とレンズの焦点距離を加味した演算を行っています。

 各頂点のスクリーン座標が定まったらワイヤーフレームの場合だとインデックスデータを元にしてそれを順番に表示するだけで完了です。
 ポリゴンの場合はそれが線ではなく三角形に変わるだけです。これはあらかじめ高速な塗りつぶし三角形描画ルーチンを作っておいたのでそれを使用しています。
 しかし、後ろが見えてしまっても構わないワイヤーフレーム(ワイヤーフレームであってもポリゴンと同じくカリングを行えば奥の方を見えなくすることはできるけど本来不要な法線ベクトルを求める必要があり処理が重くなるためこのプログラムでは行っていない)とは異なりポリゴンでは面の後ろが見えてしまっては困るためインデックスデータに入っている順番にポリゴン(三角形)を描画していくだけでは問題が出てきます。そこで、簡単な解決方法として画面奥にある三角形から順番に描画していきます。

 処理速度面からZバッファ(ドット単位で深度情報を記録していく)は実用的ではないため各頂点に重みを付けてそれによって大きな順番に並べ替えるZソートを行うことで奥のポリゴンから順に描画していきます。Zソートがどのようなものかはこちらのサイト(外部リンク)をご覧になってください。なお、このプログラムのZソートは多少fpsを犠牲にしていますが3頂点の座標を並べ替えて独自の重み付けによって極力前後関係が狂わないようにしています(単に3点の平均座標だけを元に処理した場合は4つのサンプル中でまともに表示されるのが立方体だけになってしまう)
 しかし、Zソートの原理から完全なものを作るのは不可能であり、オブジェクトの形状によってはポリゴンの前後関係が狂ってしまいポリゴン欠けが頻繁に起きてしまいます。3点すべての座標が大きいポリゴンならば手前に確実表示されるけどそうでない場合はこの重み付けのみで表示の前後関係が決まってしまうため入り組んだモデルや平面の上に平面を貼り付けたようなモデルだとポリゴン欠けが起きやすくなってしまいます。サンプルの中だとアンドアジェネシスもポリゴン数を減らすためそのようなモデルにしているため赤い四角形は非常に欠けやすくなっていますが、これはポリゴンを細かく分けて前後関係が極力狂わないようにすればZソートであってもポリゴン欠けはかなり抑えることができるようになります。

 このプログラムでは表示時に裏側となっている本来見えないポリゴンは描画しなくする陰面消去(「カリング」と呼ばれている)を行うことで処理の高速化を図っています(このプログラムにおいては処理速度重視のためワイヤーフレームではカリングOFF、ポリゴンではカリングONのみの設定となっている)。単純な方法ですが、法線ベクトルと視線ベクトルとの内積から判断しています。法線ベクトルは下記のように2つのベクトルの外積を元に計算することで求められます。

(x1,y1,z1)(x2,y2,z2)(x3,y3,z3)を3点に持つポリゴン面においてベクトルV1=(x1-x3,y1-y3,z1-z3)、ベクトルV2=(x2-x1,y2-y1,z2-z1)としたときにその外積を計算すればポリゴン面に垂直なベクトルのX成分、Y成分、Z成分は下記のようになる。

 Nx=(y1-y3)(z2-z1)-(z1-z3)(y2-y1)
 Ny=(z1-z3)(x2-x1)-(x1-x3)(z2-z1)
 Nz=(x1-x3)(y2-y1)-(y1-y3)(x2-x1)

単位ベクトル化(長さ1のベクトルにする)のためX、Y、Z成分をそれぞれSQR(Nx^2+Ny^2+Nz^2)で割れば法線ベクトルとなる。

 内積を計算する際においてcosθθは視線ベクトルと法線ベクトルとがなす角度)の示す値が負数になっていれば角度は90度以上(向かい合っている状態)となるためカメラからは見えますが正数だと見えないので簡単に判断が可能です。視線ベクトルはX、Y、Zにおいてポリゴン面の座標とカメラの座標の差分を取り単位ベクトル化をしてやれば良いです。
 しかし、カメラはZ軸上に固定であるためパースOFFの場合は下記のように単位ベクトル化する前のZ成分のみで判断することで高速化しています。(パースON時のみX、Y成分を計算)

 ポリゴン面の法線ベクトル=(Nx,Ny,Nz) ※これは単位ベクトル化する前のもの
 視線ベクトル=(0,0,1) ※パースOFFの場合

  法線ベクトルと視線ベクトルの内積より
  cosθ=Nz/SQR(Nx^2+Ny^2+Nz^2)

 分母は必ず正数になるためパースOFF時はNzの値のみでポリゴンの裏表の判断が可能になる

 シェーディングを行う場合には(あらかじめ単位ベクトル化しておいた)光源ベクトルと視線ベクトルとの内積を元に計算します。ただし、今回は90度を超えているか否かではなくちゃんと角度を求める必要があるため単位ベクトル化の必要があるのでX、Y成分も計算する必要があります。しかし、見えている面のみ法線ベクトルのY、Z方向の成分を計算することで高速化を行えているわけです。
 ただし、分母の平方根の中の計算においてプチコンで扱える524287を大きく越える値になることも多いため二乗の計算の間に1/4096を挟んで出てきた値を64倍しています。あとはcosθ(このθは視線ベクトルと光源ベクトルとのなす角度)の値から16階調のパレットのどれを使用するのかを計算します。(このプログラムは平行光源のみサポートしているためcosθ=0.5ならば単位面積に当たる光源からの光の量は正面向きの半分であり16階調中の8番目のパレットの色となる)

 あと、パースのONとOFFについて書いておきます。3次元座標をスクリーン座標に変換する場合において各頂点の座標を一般的な方法(透視投影法)で計算すれば自動的にパース(遠近感)がついてしまいます。パースはカメラの距離を離して望遠レンズで拡大することによって「望遠レンズの圧縮効果」によって少なくすることができます。これは具体的な数字を出すと同じ大きさの物体A、Bがそれぞれカメラから1m、2mの場所にある場合は距離に反比例したサイズに映るため同じ大きさにも関わらず物体Bは物体Aの縦横半分のサイズに映るのですが、これが同じ1mの距離差でも100mと101mだった場合には距離は約1%の違いしかないためカメラに映るサイズも約1%の違いになります。
 それさえ分かれば、各頂点をスクリーン座標に変換するとき距離差を0(距離を無限大で考えている)にしてやればパースをOFFにできるというのが分かると思います。これは平行投影法と呼ばれています。すべての頂点がカメラからの視差がなく平行に投影されているため上記のポリゴンの裏表の判断をする場合にもパースOFFだと法線ベクトルのX成分やY成分を考慮することなくZ成分のみで判断が可能になっているわけです。

 このように処理速度重視に偏ったプログラムであるため汎用性という観点から考えると微妙ですが、プチコンの性能を考えるとこの高速化という恩恵は大きいと思います。普通にタッチ操作でグリグリ回転させられる程度の速度(10fps以上の速度)は得られています。さすがに152ポリゴンのアンドアジェネシスは2fps弱しか出てないため非常に重いですが・・・。より高性能で汎用性の高いものを作ることは可能ですが、その場合は処理速度が犠牲になってしまいます。
 本来ならばちゃんとゲームで使えるようにライブラリの形(例えばX軸回転のルーチン、内積や外積を計算するルーチンのように処理ごとにサブルーチン化して再利用をしやすくする)にして公開したかったところですが、速度が犠牲になってしまうのでやめました。自作ゲームなどでポリゴンやワイヤーフレームを使いたいという場合にはリストを解析して必要なルーチンのみ抽出して使ってください。

  《 主な使用変数 》
CL
カメラの距離
FL
レンズの焦点距離
RL、GL、BL
光源の色
AM
環境光の強さ
PL
ポリゴンなら1、ワイヤーフレームなら0
PP
パースの有無
SH
シェーディングの有無
RX
X軸の回転量
RY
Y軸の回転量
VT
頂点数
LN、LC
ワイヤーフレームに使用している線の数、線の色
PG
使用しているポリゴンの数
V_MAX
扱える最大頂点数
L_MAX
扱える最大線数
P_MAX
扱える最大ポリゴン数
NX、NY、NZ
法線ベクトルのX成分、Y成分、Z成分
LX、LY、LZ
光源のベクトルのX成分、Y成分、Z成分
VX()、VY()、VZ()
頂点のX、Y、Z座標
WX()、WY()、WZ()
ワールド座標における頂点のX、Y、Z座標
SX()、SY()
画面上のX、Y座標
L1()、L2()
ワイヤーフレーム用インデックスデータ
P1()、P2()、P3()
ポリゴン用インデックスデータ
PC()
ポリゴン面の色データ
PZ()、PN()
ポリゴンのZソートに使用

《 実行動画 》




《 最後に 》

 私はDirect3DもOpenGLも未経験だったのですが、ワイヤーフレームや疑似3Dプログラムの経験はあったためこのプログラムのベースとなる部分は1日でできました。UIで試行錯誤したり、最適化を図ったりで完成まで結構時間がかかってしまいました(1日で作ったものを3月末まで放置していたのでデータ作成込みの実質開発期間は2週間程度)。UIに関しては自分でも納得のものになったと思います。
 ただし、自分にとっての分かりやすさを重視した仕様としたためDirect3DやOpenGL経験者にとっては使いやすいかは謎だし、そもそもプチコンで3Dを行おうという需要そのものが少ないので利用する人がいるかどうかは半信半疑ですが、良かったら使ってみてください。このサンプルプログラムのデータはすべて非圧縮なので必要に応じて圧縮を行うのも良いかもしれません。

 問題は、何に使うかですが、あらかじめ用意されている4つのデータをグリグリ動かしてもいいし、自分でモデリングしたキャラを動かしてもいいかと思います。リアルタイムに光源も自由に動かせるため立体的な感覚もつかみやすいのではないかと思います。同じモデルでカメラの位置を横にずらして2つ表示させれば平行法や交差法による立体視も可能です。このプログラムを元にして「3Dポリゴン立体視プログラム」をもこちらも作ったので参考にしてみてください。これ以外にも何か使えるものがあるかもしれません。
 自作ゲームに使用する場合はポリゴンは速度面において厳しいですが、ワイヤーフレームならそこそこ高速なのでこのルーチンを使った3Dゲームも十分作れるでしょう。アンドアジェネシスは128本で15〜16fps出ているので画面上のオブジェクト全体でこのレベルの本数(100本程度)に抑えればなんとかまともに(10〜15fps程度)プレイできそうです。ちなみにワイヤーフレームはジオメトリ処理が全体の3分の2の時間を占めておりプチコンにおいてはワイヤーフレームは表示よりも演算がボトルネックになっていると言えそうです。(三角関数の演算は超速く配列変数の読み出しより速いためテーブル化は不要なのですが、代入処理がボトルネックになっているため遅い配列変数を一旦固定変数に入れて高速化しようと思ったら逆に処理速度がダウンしてしまうくらいです。何せ実行にかかる時間は、三角関数の演算<固定変数への代入なので・・・。)

おまけ
N64ロゴ(Nキューブ)のポリゴンデータ いつものように脳内でモデリングしたものです(笑)
このプログラムを作るにあたっての簡単な経緯をこちらに書きました。(初期バージョンと比べて1割程度の高速化ですが、光源設定やシェーディングなど処理内容は2〜3割増えているため3〜4割の高速化を行ったのと同レベルです。)


RETURN/RETURN *MAIN

inserted by FC2 system