J3Wプログラミング入門

3次元ポリゴンアニメーションキット
Copyright (c) 1997 - 2003 Jun Mizutani
[INDEX] [J3Wレファレンス]

【0】はじめに
【1】最初のプログラム
【2】レジスタと繰り返し
【3】マルチプロセス
【4】インクルードファイルの使用
【5】物体の表示
【6】プロセスの引数
【7】階層構造の物体
【8】メッセージの送受信
【9】速度と重力
【10】形状の実行時生成
【11】物体を接続するポリゴン
【12】座標系の拡大縮小
【13】グラフィック画面への文字と線分の描画




【0】はじめに

J3W用のソースプログラム(定義ファイル)のプログラミングの基本の紹 介です.リファレンスマニュアル(manual.txt)ではアセンブラの知識を前 提とした記述になっていますが,ここでは,ほとんどアセンブリ言語を知ら ない方でも理解できるように努力したつもりです. BASIC, C等の高級言語と 比較すると文法も各命令の動作も単純なのでリファレンスマニュアルととも に順に追っていけば比較的簡単ではないかと思います. 正確な説明はリファ レンスマニュアルを参照してください.

アセンブラの機能とJ3Wの機能を分けて記述していません.J3DASMとJ3Wを 組み合わせて使用した場合を想定しています. LIST1からLIST10のアセンブル済みファイルは同梱してあります.

本書中に含まれるソースコードは【4】章の一部を除いて実行可能なプログ ラムとなっています.

;<-------------- ここから
;<-------------- ここまで

に囲まれた部分を切り取ってアセンブルする(詳細は後述)ことによってJ3W から実行可能です.


[TOP]

【1】最初のプログラム

まず最初のプログラムは,Hello Worldという文字列をテキストウインドウに 表示するプログラムです.グラフィックウインドウは開きません.
テキストウインドウは範囲をマウスで選択してコントロールキーとCを同時 に押すとクリップボードにコピーされます.(Windows95/98)

;<-------------- ここから
; LIST1
      OUTSTR  "Hello World"
      OUTCHR  13
      STPALL
;<-------------- ここまで

「ここから」「ここまで」をエディタ等で切り取って,例えばLIST1.J3Sとし て保存します.

Windows95/98

コマンドライン(DOSプロンプト)から
>J3DASM LIST1.J3S
のように実行するか,J3DASM.EXEのアイコンに LIST1.J3Sのアイコンをドラッ グアンドドロップするとDOSウインドウが開き,LIST1.J3Dが生成されます.こ のLIST1.J3DをJ3W.EXEのNEWボタンから指定するか,J3W.EXEのアイコンに LIST1.J3Dのアイコンをドラッグアンドドロップし,STARTボタンで実行されます.

Linux

j3wの実行には Xが必要です. ktermを開いて
$ j3dasm list1.j3s
で list1.j3s は list1.j3d へアセンブルされます.
$ j3w list1.j3d
で実行されます.

セミコロンより後ろは注釈として無視されます.
命令はすべて大文字です.ラベルは最後にコロンか続く文字列で,大文字小 文字は区別されます.詳細はマニュアルの【6】 アセンブラ仕様を参照 して下さい.

OUTSTRが文字列表示用の命令です. OUTCHR 13は改行文字を出力します. (Linux版では 13[CR] は 10[LF] に内部で変換されます.)

STPALLはすべてのプロセスを停止する命令です.この場合は1つのプロセス しかありませんが,プログラム(プロセス)の最後に置くようにします.



[TOP]

【2】レジスタと繰り返し

次はレジスタ演算,条件分岐です.

;<-------------- ここから
; LIST2
       LOAD    R1  100
  LABEL1:
       OUTNUM  R1
       OUTSTR  " Hello World"
       OUTCHR  13
       SUB     R1  10
       BPL     LABEL1:
       DELPRC
;<-------------- ここまで

LOAD R1 100 は 「R1」という名の初めから用意されている容器(レジスタと 呼びます)に100を入れます.
次の行の LABEL1: はラベルと呼びジャンプ先 を指定する場合等に使用します. LABEL1: OUTNUM R1 のように空白(半角) のあとに命令を続けることもできます. OUTNUM R1 は R1の内容を数値とし て出力します. SUB R1 10 は R1 = R1 - 10 の意味でR1の内容から10を引き ます. 次の行の BPL LABEL1: は条件分岐命令の1つで「もし結果が正かゼ ロならジャンプ」します.この場合はR1の内容が正ならばLABEL1:に戻ります.

次にR1の内容が90の状態で同様な動作をして,順次 R1の内容が80,70,60, 50,40,30,20,10,0と減少します.R1が0になったとき SUB R1 10 を実行 すると,R1は-10になり,LABEL1:にジャンプすることなく次の行,この場合 DELPRCに移ってプロセスが消滅し実行は終了します.
DELPRCは,この命令を 実行するプロセスだけを削除します.それが唯一のプロセスならばプログラ ム自体が終了します.他のプロセスを含めてすべて終了させる場合はSTPALL 命令を使用します. 無限ループのプロセスの場合でもプロセスの区切りとし てDELPRCかSTPALLを最後に置くのがいいでしょう.

レジスタは R1以外にも RQ, RL, RX, RY, RZ, RH, RP, RB, R2, R3, R4, R5, R6があります. R1からR6は数値の入れ物として使用します.RQ から RBは 数値の入れ物として使用する以外に命令によって特別な役割を持ちます.


[TOP]

【3】マルチプロセス

次は複数のプロセスを同時に実行する場合の例です. 長さの割に動作がちょっと複雑になります.

;<-------------- ここから
; LIST3
       GENPRC  ESC: 50
       LOAD    R1   0
  LABEL1:
       OUTNUM  R1
       OUTCHR  13
       ADD     R1   1
       THROW              ; この命令が重要
       BRA     LABEL1:    ; 無限ループ
       DELPRC

  ; ここから2つ目のプロセス
  ESC:
       LOAD   RQ   9
  ESC1:
       INKEY  R1          ; キ−コ−ド入力
       THROW              ; この命令が重要
       CMP    R1 0x1B
       BNE    ESC1:
       STPALL         ; 全プロセスの終了
;<-------------- ここまで

この例では,まず GENPRC ESC: 50 でプロセスを生成しています.「50個の データメモリを持つプロセスを生成して,ラベル ESC: から実行しなさい」 という意味を持ちます.この時点でもう1つのプロセス(プログラム)がESC: から実行され始めると考えてください.注意することは2番目のプロセスの R1は,最初のプロセスで使用しているR1とはまったく別の容器が用意される ということです.R1以外のレジスタ(RQ,RL,RX,RY,RZ,RH,RP,RB,R2-R6)もプ ロセス毎に別に用意されます.同様にデータメモリも別に用意されます.

ここで2つのプロセスの動作を考えます.

個々に考えるとどちらも無限ループかそれに近いものですが,2つのプロセ スが同時に実行されていると「ESCキーが押されるまで0から順に1を加えてそ れを表示する」プログラムとなります.2つめのプロセス(今後ESCプロセス と呼びます)はESCキーが押されると STPALL に処理が移り,他のすべてのプ ロセスを終了させるためです.
ただし複数のプロセスを同時に実行するとい っても実際は他のプロセスに処理を渡す必要があり(物体の移動などの時間 を指定する命令では自動的に渡される.詳細は後述),ループになるプログ ラムではTHROW命令をループ内に置いて他のプロセスに実行するチャンスを与 えてください.THROW命令があるとWindowsにも他の処理をするチャンスが与 えられます.THROW命令をループ内に置けば,安心して無限ループを持つ複数 のプロセスを同時に実行させられます.

ESCプロセスの最初の命令 LOAD RQ 9 はプロセスの識別番号を9に設定するた めの命令です.他のプロセスからメッセージを送る場合などに使用しますが, LIST3の場合は使用されていません.

【注】

INKEYによるキー入力はグラフィックウィンドウかテキストウィンドウがアク ティブになっている必要があります.アクティブでなくてもキー入力を有効に するためには以下のリストを使用してください.

;<-------------- ここから
  ESC:
       RAWKEY R1 0x1B ; キ−コ−ド入力
       THROW
       CMP    R1 0
       BEQ    ESC:
       STPALL
;<-------------- ここまで


[TOP]

【4】インクルードファイルの使用

LIST3の以下の部分をESCAPE.J3Iというファイルに保存します.

;<-------------- ここから
  ESC:
       LOAD   RQ   9
  ESC1:
       INKEY  R1          ; キ−コ−ド入力
       THROW              ; この命令が重要
       CMP    R1 0x1B
       BNE    ESC1:
       STPALL         ; 全プロセスの終了
;<-------------- ここまで

以下のように別ファイルで指定するとアセンブル時にESCAPE.J3Iが挿入され ます.LIST3と同等です.

この様に使用するファイルをインクルードファイルと呼び,J3Iという拡張子 と付けます.

;<-------------- ここから
; LIST4
       GENPRC  ESC: 50
       LOAD    R1   0
  LABEL1:
       OUTNUM  R1
       OUTCHR  13
       ADD     R1   1
       THROW              ; この命令が重要
       BRA     LABEL1:    ; 無限ループ
       DELPRC
%ESCAPE.J3I%
;<-------------- ここまで

また以下のファイルをEYE.J3Iとして保存して下さい. 視点またはカメラとして後ろの章で使用します.

;<-------------- ここから
; EYE.J3I
       GENOBJ  0  0          ; 視点用オブジェクトの生成  頂点も面も不要
       CLEARA
       LOAD    RX   -2000    ; 位置の指定 20m 後方
       SETPOS                ; 位置と角度を視点に設定
       SETEYE                ; このオブジェクトが見る
       THROW
       BCOLOR  0x000         ; 背景色を黒に設定
       GRAPHM                ; グラフィックウインドウを開く
       WAIT
       DELOBJ                ; オブジェクトの削除
       DELPRC                ; プロセスの削除
;<-------------- ここまで

よく使用するプログラムを集めてライブラリとして利用できます. インクルードファイル中にインクルードファイルを記述できます. ディレクトリは %../lib/abc.j3i% のように指定できます.



[TOP]

【5】物体の表示

物体を表示する場合は,空間に「物体」と「物体を見ている物体」が存在す る必要があります.1つのプロセスは1つの物体になることができます. したがって最低でも,最初からある1つのプロセスともう1つのプロセスが必 要になります.以下の例では最初のプロセスが空の(形のない)オブジェク ト(物体)を生成し,位置をSETPOSで設定してSETEYE命令で視点を取得しま す. 2番目のプロセス(TRIANGLE:)は3角形のオブジェクトとなります.

位置を指定するために座標を指定します. すべての物体はそれぞれ自分の向 いている方向を基準として,前がX,右がY,下がZの増加する方向です. これを座標系と呼びます.回転はZ軸回りの回転(右を向く)をヘッド回転, Y軸回りの回転(上を向く)をピッチ回転,X軸回りの回転(首を右に傾け る)をバンク回転と呼びます.

一つだけ常に存在する固定された特別な座標系があり,すべての物体の座標 系の基準となります. 北を向いて立ち,北がX,東がY,下がZとなりま す.これをワールド座標系と呼びます.【9】速度と重力で解説する重 力はワールド座標系の下方向(Zが正の方向)に働きます.

ここで使用している座標系は航空力学で使用されるNED系(X:North [前], Y:East [右],Z:Down [下] )で3次元グラフィックで使用している座標系 とは異なりますが,読み換えは簡単です. 座標値は符号付き32ビット整数の範囲(+20億〜-20億)が可能です.

あまり難しく考えず「 前がX,右がY,下がZ 」だけ覚えて下さい.

;<-------------- ここから
; LIST5
       GENPRC  TRIANGLE: 50  ;
       GENOBJ  0  0          ; 視点用オブジェクトの生成  前述のEYE.J3Iと同じ
       CLEARA
       LOAD    RX   -2000    ; 位置の指定 20m 後方
       SETPOS                ; 位置と角度を視点に設定
       SETEYE                ; このオブジェクトが見る
       THROW
       BCOLOR  0x000         ; 背景色を黒に設定
       GRAPHM                ; グラフィックウインドウを開く
       WAIT
       DELOBJ                ; オブジェクトの削除
       DELPRC                ; プロセスの削除

 TRIANGLE:  ;
       GENOBJ  6  2          ; オブジェクトの生成  6頂点 2面
       DEFPNT  0  0    500   ; 頂点0 三角形の頂点座標を登録
       DEFPNT  0  500 -500   ; 頂点1
       DEFPNT  0 -500 -500   ; 頂点2
       DEFPNT  0  0    500   ; 頂点3 頂点0と同じ
       DEFPNT  0  500 -500   ; 頂点4 頂点1と同じ
       DEFPNT  0 -500 -500   ; 頂点5 頂点2と同じ
       LOAD    R1  6         ; 面の色指定
       LOAD    R2 14
       DEFPLN  R1  3   0   1   2  ; 面の定義 表から見て左回りに指定
       DEFPLN  R2  3   5   4   3
       CLEARA                ; RX - RB の0クリア
       SETPOS                ; 初期位置と角度の設定
       ROTH    6000 2880     ; 6秒間で360度回転
       DELOBJ                ; オブジェクト
       STPALL                ; 全プロセス終了
;<-------------- ここまで

物体の生成には GENOBJ 命令に最大頂点数と最大面数を与えて生成します. 頂点数, 面数は実際に使用する数より多くても問題ありませんが,少ないと エラーが発生します.注意して下さい.視点には頂点も面も無いのでそれぞ れ,0を渡しています.見えなくても位置と角度の情報を持ちます.また, 後述(【7】章)するCHILD命令で,頂点も面も持つ子オブジェクトを持つこ ともできます.

実際に表示するためにはGRAPHM命令を実行してグラフィックウインドウを開 く必要があります.この命令はどのプロセスが実行してもかまいませんが, 複数のウインドウを開くことはできません.

形状の定義はDEFPNT命令でX,Y,Z座標を指定して1つずつ頂点を登録し ます.頂点番号はオブジェクト毎に0から順に付けられます(UPDTVP命令で変 更可能).レジスタに面の色を代入してDEFPLN命令でレジスタ,頂点数,頂 点番号列を指定することで面を定義します.面には表と裏があり,DEFPLN命 令1つでは裏からは不可視になります.

注)「ver.5.xx特有」
1つの平面の表と裏を表示するためには頂点を表と裏で共有させないで下さい. LIST5では同じ頂点を2回づつ登録しています.1平面の表と裏ではなく,例 立方体の頂点のような場合には頂点の共有は問題ありません. 1つの平面の表と裏で頂点を共有すると照明に使用する法線ベクトルが計算で きないためです.

物体の運動はROTH 6000 2880で指定しています. この場合6秒間で360度 ヘッド回転(Z軸回り)して終了します.ROTx, MOVx命令を順次実行するこ とで実行しているプロセスのオブジェクトを運動させることができます.



[TOP]

【6】プロセスの引数

プロセスは生成されるとき,親プロセスのレジスタをすべて引き継ぎます. これを利用することで,同じプログラムを複数のプロセスで共有して,与え る引数により異なった動作をさせることができます.

以下の例では3つの三角形が同じプログラムで別の動きをする例です. 視点を含めて4つのプロセスが同時に動作します.


;<-------------- ここから
; LIST6
       CLEARA                ; 引数としてレジスタに設定
       LOAD    RY  -1000
       LOAD    R4  9000      ; 時間
       LOAD    R5  2880      ; 回転角
       GENPRC  TRIANGLE: 50  ; 2つめのプロセス
       CLEARA                ; 引数としてレジスタに設定
       LOAD    RY  1000
       LOAD    R4  6000      ; 時間
       LOAD    R5  5760      ; 回転角
       GENPRC  TRIANGLE: 50  ; 3つめのプロセス
       CLEARA                ; 引数としてレジスタに設定
       LOAD    RX  1000
       LOAD    RB  720
       LOAD    R4  6000      ; 時間
       LOAD    R5  8640      ; 回転角
       GENPRC  TRIANGLE: 50  ; 4つめのプロセス

%EYE.J3I%        ; インクルードファイル 視点用オブジェクトの生成

 TRIANGLE:  ;
       GENOBJ  6  2          ; オブジェクトの生成  6頂点 2面
       DEFPNT  0  0    500   ; 頂点0 三角形の頂点座標を登録
       DEFPNT  0  500 -500   ; 頂点1
       DEFPNT  0 -500 -500   ; 頂点2
       DEFPNT  0  0    500   ; 頂点3 頂点0と同じ
       DEFPNT  0  500 -500   ; 頂点4 頂点1と同じ
       DEFPNT  0 -500 -500   ; 頂点5 頂点2と同じ
       LOAD    R1  13        ; 面の色指定
       LOAD    R2  15
       DEFPLN  R1  3   0   1   2  ; 面の定義 表から見て左回りに指定
       DEFPLN  R2  3   5   4   3
       SETPOS                ; 初期位置と角度の設定
       ROTH    R4  R5
       DELOBJ                ; オブジェクトの削除
       STPALL                ; 全プロセス終了
;<-------------- ここまで

LIST6のTRIANGLE:は回転後,直ちにオブジェクトを削除し全プロセス終了と しているため,2つめのプロセスは9秒間回転する指定であっても,最初に STPALLを実行したプロセス(6秒後)によって終了させられます.

STPALLの代わりに DELPRC命令を置くと順次プロセスが終了して物体が消え, 最後のプロセスが終了した時点で視点プロセスのみが残ります.何も存在しな いグラフィックウンドウが残ります. 終了には QUITボタンをクリックして下 さい. ROTH命令の後ろにWAIT命令を挿入した場合も,別のプロセスからメッ セージが送られるかQUITボタンをクリックするまで一時停止します.



[TOP]

【7】階層構造の物体

例えば人体のような関節を持つ物体を表現するためには階層構造を持つオブ ジェクトが必要になります. 腰をひねれば肩も腕も頭も動きます.つまり 肩も腕も首の関節も動かしていないにもかかわらず,地面に対してその位置 も角度も変化します.これは腰の座標系(フレームと呼ぶ場合もある)上に 肩の座標系が固定され,肩の座標系に頭の座標系が固定され,という具合に 親子関係を形作っています.

以下の例では同じ形の3角形の下側の頂点が関節となっています.関節は物 体の原点(0, 0, 0)の位置に来るように形状を定義すると,回転命令を普通 に使用すれば関節の動きとして表現できます.

とにかく座標系などを気にしないでLIST7を書き換えて実際に色々試してみ て下さい. 文章で読むほど難しくはないと思います.


;<-------------- ここから
; LIST7
       GENPRC  PARENT: 50    ;

%EYE.J3I%        ; インクルードファイル 視点用オブジェクトの生成

 PARENT:  ;
       BCOLOR  0x186
       GENOBJ  6 2             ; オブジェクトの生成  6頂点 2面
       CALL    def_shape:
       LOAD    RZ  1200
       SETPOS                  ; 初期位置と角度の設定
       CHILD   Child: 50 6 2   ; 子オブジェクト
       CALL    def_move:
       STPALL                  ; 全プロセス終了

 Child:  ;
       CALL    def_shape:
       LOAD    RZ  -400
       SETPOS                  ; 初期位置と角度の設定
       CHILD   GrandChild: 50 6 2
       CALL    def_move:
       STPALL                  ; 全プロセス終了

 GrandChild:  ;
       CALL    def_shape:
       LOAD    RZ  -400
       SETPOS                  ; 初期位置と角度の設定
       CHILD   GrandChild2: 50 6 2  ; このプロセスは
       CHILD   GrandChild3: 50 6 2  ; 子が2人
       CALL    def_move:
       STPALL                  ; 全プロセス終了

 GrandChild2:  ;
       CALL    def_shape:
       LOAD    RZ  -400
       LOAD    RY  -100
       SETPOS                  ; 初期位置と角度の設定
       CHILD   GrandChild3: 50 6 2
       CALL    def_move:
       STPALL                  ; 全プロセス終了

 GrandChild3:  ;
       CALL    def_shape:
       LOAD    RZ  -500
       LOAD    RY   100
       LOAD    RH   720
       SETPOS                  ; 初期位置と角度の設定
       CALL    def_move:
       STPALL                  ; 全プロセス終了

def_move:                      ; すべての物体の運動を定義
       LOAD    RL   15
    dm:
       ROTH    2000 620        ; 2秒間で回転
       ROTP    1000 360
       ROTP    1500 -360
       ROTH    1000 620        ; 2秒間で回転
       ROTB    1500 360
       ROTB    1000 -360
       LOOP    dm:
       DELOBJ
       RETURN

def_shape:                     ; すべての物体の形状を定義
       DEFPNT  0  0    0       ; 頂点0 三角形の頂点座標を登録
       DEFPNT  0  180 -400     ; 頂点1
       DEFPNT  0 -180 -400     ; 頂点2
       DEFPNT  0  0    0       ; 頂点3 頂点0と同じ
       DEFPNT  0  180 -400     ; 頂点4 頂点1と同じ
       DEFPNT  0 -180 -400     ; 頂点5 頂点2と同じ
       LOAD    R1  11          ; 面の色指定
       LOAD    R2  13
       DEFPLN  R1  3   0   1   2  ; 面の定義 表から見て左回りに指定
       DEFPLN  R2  3   5   4   3
       CLEARA                  ; RX - RB の0クリア
       RETURN
;<-------------- ここまで

LIST7の例では6関節の物体が画面中央で2分間運動します.どの関節もまっ たく同じ動き(def_move:)をしていますが,全体としては,かなり複雑な動き をしていると思いませんか? それぞれの物体の形と動きを別に定義すれば, 色々試すことができると思います.

階層型オブジェクトを実現する命令は1つだけ「CHILD」命令です. この命令は「GENPRC」と「GENOBJ」を加えた命令です.ただし「生成される オブジェクトがCHILD命令を実行したプロセスのオブジェクト(の座標系)に 属している」という点が異なります.削除は DELPRCとDELOBJを使用します.

表記法は以下の形式です.

   CHILD スタート位置のラベル  メモリサイズ  頂点数  ポリゴン数
         ←─────GENPRC───────→  ←──GENOBJ──→

親オブジェクトが先に消滅した場合は,その子供たちはそれぞれ空間内で独 立したオブジェクトになります.



[TOP]

【8】メッセージの送受信

複数のプロセスが独立して運動可能であることは,これまで見てきました. さて,相互作用がある場合,例えば弾丸が「おまえに命中したぞ!」と当っ た相手に伝えて,それなりの行動を期待する時,プロセスがどのように意志 疎通を行えばいいのでしょうか? これまでに何度も出てきた STPALL がヒン トになります.STPALLは存在する他のプロセスに対して「皆さん,もう終わ りだよ!後始末をして撤収!」とメッセージ(シグナルともいう)を放送し ています.これを特定の相手(プロセス)に特定のメッセージを送ることが できれば目的は達成できます.

入力キーコードをプロセス2に送るプロセスと受信したメッセージを表示する プロセスの例です.

;<-------------- ここから
; LIST8
       GENPRC  PROC2: 50
       LOAD    RQ  1
    key:
       INKEY   R1
       CMP     R1  0
       BEQ     next:
       SEND    2   R1
     next:
       THROW
       BRA     key:
       DELPRC

  PROC2:
       LOAD    RQ 2
    loop:
       WAIT
       RECEIV  R1
       OUTNUM  R1
       OUTCHR  13
       CMP     R1 0x1B
       BEQ     exit:
       BRA     loop:
    exit:
       STPALL
;<-------------- ここまで

ここで LOAD RQ 1 はプロセスのIDを1に設定する命令です.RQレジスタ に設定されている値がプロセスの識別番号になります.プロセス生成直後は すべてのレジスタがプロセスを生成したプロセスから引き継がれるためプロ セスを特定するためにはRQを再設定する必要があります.プロセスのIDが 重複する場合はシステムが管理しているプロセス管理番号の最も若いプロセ スにメッセージが渡されます.

同時に複数のプロセスが1つのプロセスに対してメッセージを送る場合もあ ります.この場合は最も大きい値のメッセージが優先されます.またメッセ ージの送出元のプロセスを識別する事はできません.プロセス間で同期しな がら複雑な動作をする場合は共有メモリを使用する必要があるでしょう. 複数のプロセス間の同期は難しい問題です.はじめはプロセスが1対1の場 合から実験して見てください.

プロセス管理番号はDISTNC命令でのみ取得できます.同一のプロセス番号を 持つプロセスを識別できます.プロセス管理番号を指定してメッセージを送 るにはSENDTO命令を使用します.同一のプロセス番号を使用する事は混乱の 元となります.なるべく避けてください.



[TOP]

【9】速度と重力

物体が勝手に運動する例です.以下のリストでは1つの立方体が速度を持ち, 重力の影響を受けながら壁にあたると反転して跳ね回ります.衝突は立方体 の重心座標で判定していますので床と後ろの壁とのオブジェクト間の衝突判 定はしていません.床には立方体の影が動いています.


;<-------------- ここから
; LIST9
;  立方体の弾性衝突  物体の重力,速度属性のデモ
       GENPRC  ESC: 50         ; ESCキーで終了させるプロセス
       GENOBJ  0 0             ; 視点用オブジェクトの生成
       CLEARA
       LOAD    RX   -2000      ; 位置の指定 20m 後方
       LOAD    RZ   -1000      ; 位置の指定 10m 上方
       SETPOS                  ; 位置と角度をオブジェクトに設定
       SETEYE                  ; 視点の設定
       GENPRC  CUBE0: 50       ; 跳ね回る立方体のプロセス
       GENPRC  SHADOW: 50      ; 立方体の影となるプロセス
       GENPRC  FLOOR: 50       ; 床 動かない
       GENPRC  WALL: 50        ; 壁 動かない
       THROW
       BCOLOR  0x100           ; 背景色を黒に設定
       GRAPHM                  ; グラフィックモードに変更
       WAIT
       DELOBJ                  ; オブジェクトの削除

;  立方体のプロセス 不可視 位置をコントロール
     CUBE0:
       LOAD    RQ  777
       GENOBJ  0  0
       CHILD   CUBE1: 50 8 6
       CLEARA                  ; RX - RB の0クリア
       LOAD    RZ  -2000
       SETPOS                  ; 初期位置と角度の設定
       LOAD   R1 980000        ; 重力加速度 = 980cm/s^2 x 1000
       SETGRV R1               ; 重力加速度の設定
       CLEARA
       LOAD   RX  170000
       LOAD   RY  250000
       SETVEL                  ; 慣性速度を設定
   Loop:
       CALL    BOUNCE:  ; 立方体の跳ね返り処理用手続きを呼ぶ
       THROW
       BRA     Loop:
       STPALL           ; 全プロセス終了

;  立方体のプロセス 可視部分
     CUBE1:
       LOAD    RQ  666
;       GENOBJ  8 6            ; オブジェクトの生成
       SETREF  50              ; シェイディングの明るい方50%使用
       DEFPNT  150  150 -150   ; 頂点0  立方体の頂点座標を登録
       DEFPNT -150  150 -150   ; 頂点1
       DEFPNT -150 -150 -150   ; 頂点2
       DEFPNT  150 -150 -150   ; 頂点3
       DEFPNT  150  150  150   ; 頂点4
       DEFPNT -150  150  150   ; 頂点5
       DEFPNT -150 -150  150   ; 頂点6
       DEFPNT  150 -150  150   ; 頂点7
       LOAD   R1  14           ; 面の色指定
       DEFPLN R1  4   0   1   5   4 ; 面の設定
       DEFPLN R1  4   3   7   6   2
       DEFPLN R1  4   1   2   6   5
       DEFPLN R1  4   0   4   7   3
       DEFPLN R1  4   4   5   6   7
       DEFPLN R1  4   0   3   2   1
   Loop2:
       ROTH   3000 1440        ; 親座標系内で3秒間で180度回転するだけ
       BRA    Loop2:
       DELOBJ
       DELPRC

;  立方体の跳ね返り処理用サブルーチン
    BOUNCE:
       GETPOS                  ; 現在位置を取得
       LOAD   RH  RX           ; RH := position.x
       LOAD   RP  RY           ; RP := position.y
       LOAD   RB  RZ           ; RB := position.z
       LOAD   R1  0            ; Change Flag
       GETWVL                  ; 現在の速度を取得
       CMP    RH  850          ; 後ろの壁への衝突チェック
       BMI    B1:
       AND    RX  RX
       BMI    B1:
       NEG    RX  RX           ; if pos.x > 850 then vx = -vx
       LOAD   R1  1            ; Change := True
   B1: CMP    RH  -850         ; 前の壁への衝突チェック
       BPL    B2:
       AND    RX  RX
       BPL    B2:
       NEG    RX  RX           ; if pos.x > 850 then vx = -vx
       LOAD   R1  1            ; Change := True
   B2: CMP    RP  850          ; 右の壁への衝突チェック
       BMI    B3:
       AND    RY  RY
       BMI    B3:
       NEG    RY  RY           ; if pos.y > 850 then vy = -vy
       LOAD   R1  1            ; Change := True
   B3: CMP    RP  -850         ; 左の壁への衝突チェック
       BPL    B4:
       AND    RY  RY
       BPL    B4:
       NEG    RY  RY           ; if pos.y < -850 then vy = -vy
       LOAD   R1  1            ; Change := True
   B4: CMP    RB  -150         ; 床への衝突チェック
       BMI    B5:
       AND    RZ  RZ
       BMI    B5:
       NEG    RZ  RZ           ; if pos.z > -150 then vz = -vz
       LOAD   R1  1            ; Change := True
   B5: CMP    R1  1            ; 運動の方向に変化があれば速度を再設定
       BNE    B6:
       NOTE    9 50 127
       SETWVL
   B6: RETURN                  ; リターン

; 影のプロセス
   SHADOW:
       GENOBJ  4 2             ; オブジェクトの生成
       DEFPNT  150  150 0      ; 頂点0  正方形の頂点座標を登録
       DEFPNT -150  150 0      ; 頂点1
       DEFPNT -150 -150 0      ; 頂点2
       DEFPNT  150 -150 0      ; 頂点3
       LOAD   R1  16           ; 面の色指定  常に黒
       DEFPLN R1  4   3   2   1   0
   SH1: PRCPOS  777            ; 立方体の位置を取得
       LOAD    RZ  -5          ; 高さを床面の少し上に設定
       PUSH    RX              ; 立方体の位置を保存
       PUSH    RY
       PUSH    RZ
       PRCPOS  666             ; 立方体の角度を取得
       POP     RZ              ; 立方体の位置を復帰
       POP     RY
       POP     RX
       SETPOS                  ; 初期位置と角度の設定
       THROW
       BRA     SH1:
       WAIT
       STPALL                  ; 全プロセス終了

;  床のプロセス
   FLOOR:
       GENOBJ  4 2             ; オブジェクトの生成
       LOAD    R1  40000
       PRIOR   R1
       DEFPNT  1000  1000 0    ; 頂点0  正方形の頂点座標を登録
       DEFPNT -1000  1000 0    ; 頂点1
       DEFPNT -1000 -1000 0    ; 頂点2
       DEFPNT  1000 -1000 0    ; 頂点3
       LOAD   R1  28           ; 面の色指定
       DEFPLN R1  4   3   2   1   0
       CLEARA                  ; RX - RB の0クリア
       SETPOS                  ; 初期位置と角度の設定
       WAIT                    ; 静止
       STPALL                  ; 全プロセス終了

;  後壁の登録
   WALL:
       GENOBJ  4 2             ; オブジェクトの生成
       DEFPNT  1000  1000 0    ; 頂点0
       DEFPNT  1000 1000 -2000 ; 頂点1
       DEFPNT 1000 -1000 -2000 ; 頂点2
       DEFPNT  1000 -1000 0    ; 頂点3
       LOAD   R1  13           ; 面の色指定
       DEFPLN R1  4   0   1   2   3
       CLEARA                  ; RX - RB の0クリア
       SETPOS                  ; 初期位置と角度の設定
       WAIT                    ; 静止
       STPALL                  ; 全プロセス終了

%ESCAPE.J3I%
;<-------------- ここまで

この例では7個のプロセスが存在しますが,ESCキーチェックと立方体の位置 と立方体と影のプロセスが動いているだけです.他のプロセスは終了を待っ ています.立方体の位置プロセスは自分の座標をチェックして範囲外なら方 向を反転しているだけです. 立方体の形状プロセスは単にヘッド回転して いるだけです.影のプロセスは立方体の位置を見て,さらに立方体の形状か ら角度を取得して自分を同じ位置の高さ0に置くことを繰り返しているだけで す. 重力,加速度,速度の効果はシステムが画面表示する前に自動的に処理 します.

ここで立方体のプロセスを2つに分けている理由は,立方体がどのように回 転しても地面との角度を固定するためです.自分が回転してしまうと運動の 方向の前後左右が回転してしまうためです.座標が回転しないプロセスの子 オブジェクトとして回転する立方体の形状オブジェクトがあります.

重力を有効にするには,重力の効果が必要なオブジェクト毎に

       LOAD   R1 980000        ; 重力加速度 980cm/s^2 x 1000
       SETGRV R1

の様に設定します. SETGRV に渡す値は16ビットの整数またはレジスタで指 定します. 980000は16ビット整数の範囲にないため,レジスタで渡していま す. これは地球上の重力加速度ですが,2322600を使用すれば木星赤道上の 運動をシミュレートできます.ちなみに月面では166600です.

重力,速度,加速度は1000倍した値を与える必要があります.詳細はリファ レンスマニュアルを参照して下さい. 距離の単位としてcmを使用しています が,プログラム全体で合わせれば距離の単位は任意です.

LIST9の例では一辺3mの立方体を重心が20mの位置から落として床で跳ね返り ます.つまり18.5m落ちて跳ね返り,20mの位置まで上昇して落ちはじめます. 計算上1.943秒で18.5m落ちるはずです.マシンの速さにかかわらず同じ速度 になると思います.試して見てください.

跳ね返り処理中 NOTE 9 50 127 の行でMIDIの9チャンネルから音を出し ています.パーカション系の音が出ているはずです.

もっともらしいフライトシミュレータを作成する場合は重力の影響を表現す る必要があると思います.バンクして水平旋回等を表現できます.



[TOP]

【10】形状の実行時生成

形状をプログラム作成時に定義しておくのではなく,実行時にプログラムに 生成させることができます. 以下の例は3角柱を生成するサブルーチンを 呼出しています.

;<-------------- ここから
; LIST10
       GENPRC  TRI: 50         ; 3角柱のプロセスを生成

%EYE.J3I%        ; インクルードファイル 視点用オブジェクトの生成

   TRI:
       GENOBJ  16  10          ; オブジェクトの生成  16頂点 10面
       LOAD    RH  500
       LOAD    R1  400
       LOAD    R2  400
       LOAD    R3  12
       CALL     Bar33:         ; 面と頂点の生成
       CLEARA
       LOAD    RP 720
       SETPOS                  ; 位置の設定
       LOAD    RP 1720
       LOAD    RB 2720
       MOVALL  20000
       STPALL                  ; 全プロセス終了

  ;---------------------------------------------------
  ;  3角柱
  ;             L1        L1 は長さ
  ;         +--------+
  ;      R1 *origin  |R2  → X
  ;         +--------+
  ;           Rx は正3角形の中心から頂点までの距離(30000以下のこと)
  ;    RH:L1
  ;    R1:R1, R2:R2, R3:COLOR
  ;    RX,RY,RZ:破壊     RP,RB,R4,R5,R6:保存
  ;    頂点 6 面 5
  ;---------------------------------------------------
  Bar33:
       LOAD   RX  0
       CALL   DEF_TRIPOINT:
       ADD    RX  RH
       LOAD   R1  R2
       CALL   DEF_TRIPOINT:
       DEFPLN R3 3   2   1   0
       DEFPLN R3 3   3   4   5
       DEFPLN R3 4   0  1  4  3     ;     3
       DEFPLN R3 4   1  2  5  4     ;     0
       DEFPLN R3 4   2  0  3  5     ;    2 1
                                    ;  5     4
       RETURN

  ;---------------------------------------------------
  ; 3角形の頂点の定義
  ;  R = 正3角形の中心から頂点までの距離(30000以下のこと)
  ;  P = SQRT(R*R*3)/2
  ;  Q = R/2               o→y
  ;         Z      Y      ↓         0
  ;    0   -R      0       z     / \
  ;    1    Q      P           /  .  \
  ;    2    Q     -P          2 ------- 1
  ;  ENTER R1 = R, RX = X座標,  それ以外は保存される
  ;---------------------------------------------------
    DEF_TRIPOINT:  ; 頂点座標を計算で求める
       PUSHG
       PUSHA
       LOAD   R2 R1       ; R1 = R
       MUL    R2 R2
       MUL    R2 3
       SQRT   R2 R2       ; R2 = P = SQRT(R*R*3)
       DIV    R2 2
       LOAD   R3 R1
       DIV    R3 2        ; R3 = Q = R/2
       NEG    R4 R1       ; -R
       NEG    R5 R2       ; -P
       NEG    R6 R3       ; -Q
       LOAD   RZ R4       ; -R
       LOAD   RY 0
       POINT              ;  頂点の登録(0)
       LOAD   RZ R3       ;  Q
       LOAD   RY R2       ;  P
       POINT              ;  頂点の登録(1)
       LOAD   RZ R3       ;  Q
       LOAD   RY R5       ; -P
       POINT              ;  頂点の登録(2)
       POPA
       POPG
       RETURN
;<-------------- ここまで

さらに詳細な例は REVOLUTION.J3Iを参照して下さい.任意の回転体を生成 することができます.

[TOP]

【11】物体を接続するポリゴン

例えば腕を曲げる場合には肘の皮膚は伸び縮みします.動物の体は骨と それを取り巻く筋肉,そして皮膚でできています.これまでの例では 多角形の大きさは定義したまま変化することはありませんでした.

階層構造の物体(【7】章)では親オブジェクトが存在して頂点を持つ場合 には,多角形の頂点番号に負の数を使用して親オブジェクトの頂点を指定 する事ができます.独立して運動する物体間に多角形(スキン)を張る事が できます.こうして,例えば肘の関節に伸び縮みする皮膚で腕を接続しま す.負の数を使用して親オブジェクトの頂点を指定するため,親の0番頂点 は指定できないことに注意して下さい.

;<-------------- ここから
; LIST11
       GENPRC  PARENT: 50      ; 親のプロセスを生成

%EYE.J3I%        ; インクルードファイル 視点用オブジェクトの生成

  PARENT:
       GENOBJ  8  5          ; 親オブジェクトの生成  8頂点 5面
       CHILD   CHILD1: 50  8  13 ; 子オブジェクトの生成  8頂点13面
       DEFPNT  200  200  0   ; 頂点0
       DEFPNT -200  200  0   ; 頂点1  3 ---------- 0 z=0
       DEFPNT -200 -200  0   ; 頂点2  |            |
       DEFPNT  200 -200  0   ; 頂点3  |   7    4   | z=-2000
       DEFPNT  200  200 -1000; 頂点4  |   6    5   |
       DEFPNT -200  200 -1000; 頂点5  |            |
       DEFPNT -200 -200 -1000; 頂点6  2 -----------1
       DEFPNT  200 -200 -1000; 頂点7
       LOAD    R1  15        ; 面の色指定
       DEFPLN  R1  4   0   1   2   3; 面の定義 表から見て左回りに指定
       DEFPLN  R1  4   0   3   7   4
       DEFPLN  R1  4   0   4   5   1
       DEFPLN  R1  4   5   6   2   1
       DEFPLN  R1  4   6   7   3   2
       CLEARA
       LOAD    RZ  1000
       SETPOS                  ; 位置の設定
    pa1:
       ROTH  20000 2880
       ROTH  20000 -2880
       BRA    pa1:
       STPALL                  ; 全プロセス終了

  CHILD1:
       DEFPNT  200  200 -300 ; 頂点0
       DEFPNT -200  200 -300 ; 頂点1  3 ---------- 0 z=-1000
       DEFPNT -200 -200 -300 ; 頂点2  |            |
       DEFPNT  200 -200 -300 ; 頂点3  |   7    4   | z=-2000
       DEFPNT  200  200 -1000; 頂点4  |   6    5   |
       DEFPNT -200  200 -1000; 頂点5  |            |
       DEFPNT -200 -200 -1000; 頂点6  2 -----------1
       DEFPNT  200 -200 -1000; 頂点7
       LOAD    R1  11        ; 面の色指定
       DEFPLN  R1  4   7   6   5   4; 面の定義 表から見て左回りに指定
       DEFPLN  R1  4   0   3   7   4
       DEFPLN  R1  4   0   4   5   1
       DEFPLN  R1  4   5   6   2   1
       DEFPLN  R1  4   6   7   3   2
       ; 関節部の面を登録
       LOAD    R1  4         ; 面の色指定
       DEFPLN  R1  3  -4   3   0 ; ねじれる可能性があるため三角形を貼る
       DEFPLN  R1  3  -4  -7   3 ; -7 ---------- -4  親の頂点
       DEFPLN  R1  3  -4   0   1 ;  |            |
       DEFPLN  R1  3  -5  -4   1 ;  |   3    0   |   子の頂点
       DEFPLN  R1  3   1   2  -6 ;  |   2    1   |
       DEFPLN  R1  3  -6  -5   1 ;  |            |
       DEFPLN  R1  3   2   3  -7 ; -6 ---------- -5
       DEFPLN  R1  3  -7  -6   2

       CLEARA
       LOAD    RZ  -1300
       SETPOS                  ; 位置の設定
    ch1:
       ROTP   3000 720
       ROTP   6000 -1440
       ROTP   3000 720
       ROTH   3000 360
       ROTH   6000 -720
       ROTH   3000 360
       BRA    ch1:
       STPALL                  ; 全プロセス終了
;<-------------- ここまで

この例を実行して,赤い面がスキンにあたります.伸び縮みして変形している ことが分かります.ここでは親物体1つと子物体1つですが,親1つに複数の 子を持つ場合も同様に各々の子が親の頂点を指定できます.子は常に親の頂点 だけ参照することができます.



[TOP]

【12】座標系の拡大縮小

例えばビルが立ち並ぶ世界を作成するとします.1つ1つのビルは地面に固定さ れ,動くことはありません.色々なサイズの直方体を登録する必要があります. 指定したサイズの直方体の頂点を計算して登録するプログラムもできますが. 高さ,幅,奥行きを拡大縮小することができれば,1つの大きさの立方体を登 録するルーチンを作成して,どのビルのプロセスもそのルーチンを呼び出した 後,高さ,幅,奥行きの拡大率を設定するだけで大きさの異なる直方体を作成 することができます.

物体が属している局所座標系を拡大縮小することによって,登録済みの物体の 形状を後から変更することができます.親子関係にある物体の場合も1個所だ け変更することができます.例えば,足が徐々に伸びるなどの表現ができるよ うになります.

SETSCL, GETSCL, SCALE命令は物体の所属する座標系の縮尺を設定,取得,変 更することができます.

以下のサンプルは簡単な人型の物体のアニメーションですが,ここでは特に 局所座標系のスケールの変更のデモンストレーションのために,すべて一辺の 長さが100の立方体のみで作成してみました.

J3Wには現在モデラーが用意されていませんが,モデラーを使用しなくても, ちょっとした3DCGのアニメーションを作成できる例としたつもりです.


;<-------------- ここから
; LIST12
       GENPRC  BODY: 50      ; 親のプロセスを生成

       ; デフォルトプロセスは視点オブジェクトになる
       GENOBJ  0  0          ; 視点用オブジェクトの生成  頂点も面も不要
       CLEARA
       LOAD    RX   -1000    ; 視点の位置の指定
       SETPOS                ; 位置と角度を視点に設定
       SETEYE                ; このオブジェクトが見る
       THROW
       BCOLOR  0x84A         ; 背景色を設定
       GRAPHM                ; グラフィックウインドウを開く
       WAIT
       DELOBJ                ; オブジェクトの削除
       DELPRC                ; プロセスの削除

  BODY:
       GENOBJ  8  6              ; 親オブジェクトの生成 胴体
       CALL    CUBE100:
       CHILD   R_ARM:  50  8  6  ; 子オブジェクトの生成 右腕
       CHILD   L_ARM:  50  8  6  ; 子オブジェクトの生成 左腕
       CHILD   R_THIGH: 50  8  6 ; 子オブジェクトの生成 右大腿部
       CHILD   L_THIGH: 50  8  6 ; 子オブジェクトの生成 左大腿部
       CHILD   HEAD:   50  8  6  ; 子オブジェクトの生成 頭
       LOAD    RX  3000        ; X軸の縮尺
       LOAD    RY  2000        ; Y軸の縮尺
       LOAD    RZ  1000        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RP  720
       SETPOS                  ; 位置の設定
    bd1:
       ROTB   3000 720         ; 全体の動作の定義
       ROTB   6000 -1440       ; X軸まわりの回転
       ROTB   3000 720
       ROTH   3000 360         ; Z軸まわりの回転
       ROTH   6000 -720
       ROTH   3000 360
       LOAD    RX  2000        ; X軸の縮尺
       LOAD    RY  2000        ; Y軸の縮尺
       LOAD    RZ  2000        ; Z軸の縮尺
       SCALE   4000            ; 大きくなる
       LOAD    RX   500        ; X軸の縮尺
       LOAD    RY   500        ; Y軸の縮尺
       LOAD    RZ   500        ; Z軸の縮尺
       SCALE   5000            ; 小さくなる
       BRA    bd1:             ; ずっと繰り返し
       STPALL                  ; 全プロセス終了(一応入れておく)

  HEAD:     ; 頭
       CALL    CUBE100:        ; 立方体の形状を設定
       CLEARA
       LOAD    RX  120
       SETPOS                  ; 位置の設定
    hd1:                       ; 頭部の動作
       LOAD    RX  2000        ; X軸の縮尺
       LOAD    RY  2000        ; Y軸の縮尺
       LOAD    RZ  2000        ; Z軸の縮尺
       SCALE   5000            ; 大きくなる
       LOAD    RX   500        ; X軸の縮尺
       LOAD    RY   500        ; Y軸の縮尺
       LOAD    RZ   500        ; Z軸の縮尺
       SCALE   5000            ; 小さくなる
       BRA    hd1:             ; ずっと繰り返し
       WAIT                    ; この命令は無意味
       STPALL                  ; 全プロセス終了(一応入れておく)

  R_ARM:    ;  右腕
       CHILD   R_FARM:  50  8  6 ; 子オブジェクトの生成 右腕
       CALL    CUBE100:        ; 立方体の形状を設定
       LOAD    RX  1500        ; X軸の縮尺
       LOAD    RY   700        ; Y軸の縮尺
       LOAD    RZ   700        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RX  75          ; 親座標系で測った関節の位置
       LOAD    RY  75
       LOAD    RH  720
       SETPOS                  ; 位置の設定
    ra1:
       ROTP   2000 720
       ROTP   4000 -1440
       ROTP   2000 720
       BRA    ra1:             ; ずっと繰り返し
       WAIT                    ; この命令は無意味
       STPALL                  ; 全プロセス終了(一応入れておく)

  L_ARM:    ;  左腕
       CHILD   L_FARM:  50  8  6 ; 子オブジェクトの生成 右腕
       CALL    CUBE100:        ; 立方体の形状を設定
       LOAD    RX  1500        ; X軸の縮尺
       LOAD    RY   700        ; Y軸の縮尺
       LOAD    RZ   700        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RX  75          ; 親座標系で測った関節の位置
       LOAD    RY -75
       LOAD    RH  -720
       SETPOS                  ; 位置の設定
    la1:
       ROTP   2000 720         ; 左腕の動作
       ROTP   4000 -1440
       ROTP   2000 720
       BRA    la1:             ; ずっと繰り返し
       WAIT                    ; この命令は無意味
       STPALL                  ; 全プロセス終了(一応入れておく)

  R_FARM:   ;  右前腕
       CALL    CUBE100:        ; 立方体の形状を設定
       LOAD    RX  1500        ; X軸の縮尺
       LOAD    RY   800        ; Y軸の縮尺
       LOAD    RZ   800        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RX  120
       SETPOS                  ; 位置の設定
    rfa1:
       ROTP   2500 360         ; 前腕部の動作
       ROTP   2500 -360
       BRA    rfa1:            ; ずっと繰り返し
       WAIT                    ; この命令は無意味
       STPALL                  ; 全プロセス終了(一応入れておく)

  L_FARM:   ;  左前腕
       CALL    CUBE100:        ; 立方体の形状を設定
       LOAD    RX  1500        ; X軸の縮尺
       LOAD    RY   800        ; Y軸の縮尺
       LOAD    RZ   800        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RX  120
       SETPOS                  ; 位置の設定
    lfa1:
       ROTP   2500 360         ; 前腕部の動作
       ROTP   2500 -360
       BRA    lfa1:            ; ずっと繰り返し
       WAIT                    ; この命令は無意味
       STPALL                  ; 全プロセス終了(一応入れておく)

  R_THIGH:  ; 右大腿部
       CHILD   R_LEG:  50  8  6  ; 子オブジェクトの生成 右腕
       CALL    CUBE100:        ; 立方体の形状を設定
       LOAD    RX  2000        ; X軸の縮尺
       LOAD    RY   700        ; Y軸の縮尺
       LOAD    RZ   700        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RX  -10         ; 親座標系で測った関節の位置
       LOAD    RY   25
       LOAD    RH  -1440
       SETPOS                  ; 位置の設定
       WAIT                    ; ここでは何も動作していない
       STPALL                  ; 全プロセス終了(一応入れておく)

  L_THIGH:  ; 左大腿部
       CHILD   L_LEG:  50  8  6  ; 子オブジェクトの生成 右腕
       CALL    CUBE100:        ; 立方体の形状を設定
       LOAD    RX  2000        ; X軸の縮尺
       LOAD    RY   700        ; Y軸の縮尺
       LOAD    RZ   700        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RX  -10         ; 親座標系で測った関節の位置
       LOAD    RY  -25
       LOAD    RH  -1440
       SETPOS                  ; 位置の設定
       WAIT                    ; ここでは何も動作していない
       STPALL                  ; 全プロセス終了(一応入れておく)

  R_LEG:    ;  右足
       CALL    CUBE100:        ; 立方体の形状を設定
       LOAD    RX  2000        ; X軸の縮尺
       LOAD    RY   800        ; Y軸の縮尺
       LOAD    RZ   800        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RX  120
       SETPOS                  ; 位置の設定
       WAIT                    ; ここでは何も動作していない
       STPALL                  ; 全プロセス終了(一応入れておく)

  L_LEG:    ;  左足
       CALL    CUBE100:        ; 立方体の形状を設定
       LOAD    RX  2000        ; X軸の縮尺
       LOAD    RY   800        ; Y軸の縮尺
       LOAD    RZ   800        ; Z軸の縮尺
       SETSCL                  ; 縮尺の設定
       CLEARA
       LOAD    RX  120
       SETPOS                  ; 位置の設定
       WAIT                    ; ここでは何も動作していない
       STPALL                  ; 全プロセス終了(一応入れておく)


  CUBE100:                    ; 8頂点6面の立方体
       DEFPNT    0   50 -50   ; 頂点0      奥
       DEFPNT    0   50  50   ; 頂点1  7 ---------- 4 x=100
       DEFPNT    0  -50  50   ; 頂点2  |            |
       DEFPNT    0  -50 -50   ; 頂点3  |  3 ---- 0  | x=0
       DEFPNT  100   50 -50   ; 頂点4  |  2 手前 1  |
       DEFPNT  100   50  50   ; 頂点5  |            |
       DEFPNT  100  -50  50   ; 頂点6  6 -----------5
       DEFPNT  100  -50 -50   ; 頂点7
       LOAD    R1  15         ; 面の色指定  ( テキスト参照 )
       DEFPLN  R1  4   0   3   2   1; 面の定義 表から見て左回りに指定
       DEFPLN  R1  4   4   0   1   5
       DEFPLN  R1  4   1   2   6   5
       DEFPLN  R1  4   2   3   7   6
       DEFPLN  R1  4   0   4   7   3
       DEFPLN  R1  4   4   5   6   7
       RETURN
;<-------------- ここまで

例としてはチョット長くなってしまいました.画面を見ながら修正していくと, ドンドン長くなってしまいます.上の例では足に動きを付けていません.

腕の部分と同様に動きを設定することができます.さらにキー入力をチェック して各プロセスにメッセージを送るプロセスを追加し,メッセージを判断して 各関節の動作を決定するように変更すれば格闘ゲームも可能でしょう.

また CUBE100:中

       LOAD    R1  15         ; 面の色指定

の行を削除して,CALL CUBE100: と呼び出している部分を

       LOAD    R1  1          ; パーツの色指定
       CALL    CUBE100:       ; 一辺の長さ100の立方体の登録

のように変更すると,各パーツの色を独立に設定できるようになります.



[TOP]

【13】グラフィック画面への文字と線分の描画

グラフィックウィンドウに文字と線分を重ね書きをすることができます. フライトシミュレータのヘッドアップディスプレイの表示のように, 例えば物体の位置,角度,経過時間などをリアルタイムに表示する場合に 使用できます.この2次元の文字と線分は一旦書き込むと常に表示されます.

文字の描画は GRCOLで表示色を設定し,GRCSRで位置を設定します.
この位置に設定は左上隅が 0 右下隅が 1999の1次元で指定します. 2次元で指定できないので少し面倒ですが (80*行)+桁 で計算できます.
GRCSRで位置を指定した後は,GRSTR(文字列),GRNUM(数値),GRCHR(文字)は 書き込み位置は更新されて続けて書き込まれます.

ウィンドウに直接描画する線分はウィンドウのピクセル位置(640x480) で位置を指定します.この線分は登録制となっていて,0番から99番の 100本までです.登録された線分は位置を書き換えるか,GRLINCで 消去されるまで表示されたままになります.
線分を表示する場合は以下の様にレジスタに設定したのち,GRLINE命令 を実行します.
RX x0 始点
RY y0
RZ
RH x1 終点
RP y1
RB ライン番号(0 - 99)

以下の例では 3次元の回転する3角形に,0.5秒ごとに表示される文字列と 高速に書き換わる2次元の線分が重ね書きされて1分間後に終了します.

;<-------------- ここから
; LIST13

       GENPRC  TRIANGLE: 50  ; 3角形の物体のプロセス
       GENPRC  LINEDEMO: 50  ; 2次元の線分表示
       GENPRC  STR_DEMO: 50  ; 文字表示プロセス
       GENOBJ  0  0          ; 視点用オブジェクトの生成
       CLEARA
       LOAD    RX   -1000    ; 位置の指定
       SETPOS                ; 位置と角度を視点に設定
       SETEYE                ; このオブジェクトが見る
       THROW
       BCOLOR  0x000         ; 背景色を黒に設定
       GRAPHM                ; グラフィックウインドウを開く
       WAIT
       DELOBJ                ; オブジェクトの削除
       DELPRC                ; プロセスの削除

 TRIANGLE:  ;
       GENOBJ  6  2          ; オブジェクトの生成  6頂点 2面
       DEFPNT  0  0    500   ; 頂点0 三角形の頂点座標を登録
       DEFPNT  0  500 -500   ; 頂点1
       DEFPNT  0 -500 -500   ; 頂点2
       DEFPNT  0  0    500   ; 頂点3 頂点0と同じ
       DEFPNT  0  500 -500   ; 頂点4 頂点1と同じ
       DEFPNT  0 -500 -500   ; 頂点5 頂点2と同じ
       LOAD    R1  5         ; 面の色指定
       LOAD    R2 14
       DEFPLN  R1  3   0   1   2  ; 面の定義 表から見て左回りに指定
       DEFPLN  R2  3   5   4   3
       CLEARA                ; RX - RB の0クリア
       SETPOS                ; 初期位置と角度の設定
       ROTH    60000 28800   ; 60秒間で10回転
       DELOBJ                ; オブジェクト
       STPALL                ; 全プロセス終了

; ---------------------------------------------------
;   0.5秒ごとに文字列を表示するプロセス
; ---------------------------------------------------
 STR_DEMO:
       GRCOL  7
       GRCLR                 ; 画面上の文字をすべて消去
       LOAD   RL  30
    sd1:
       LOAD   RB  RL
       CALL   RandomStr:
       NOOP   500            ; 0.5秒待つ 待たない場合はTHROWを置く
       LOOP   sd1:
       BRA    STR_DEMO:      ; 30回表示したら最初から
       STPALL                ; 意味はないがプロセスの区切りを明確に

; ---------------------------------------------------
;   ランダムな位置に文字列を表示
; ---------------------------------------------------
 RandomStr:
       LOAD   R2   80
       RANDOM RX   R2        ; 0 - 79 の乱数
       LOAD   R2   25
       RANDOM RY   R2        ; 0 - 24 の乱数
       MUL    RY   80
       ADD    RX   RY        ; RX = (80 * y) + x で表示位置を計算
       GRCSR  RX             ; 表示位置を設定
       GRSTR  " NUMBER = "   ; 文字列の表示
       LOAD   R2   100000
       RANDOM RX   R2        ; 0 - 99999 の乱数
       GRNUM  RX             ; 数値の表示
       GRCHR  ' '            ; 続けて空白を1つ書き込み
       RETURN

; ---------------------------------------------------
;   ライン表示プロセス 30本の線分を書き換え続ける
; ---------------------------------------------------
 LINEDEMO:
       LOAD   RL  30
    ld1:
       LOAD   RB  RL         ; 1番から30番の線分を順に書きかえる
       CALL   RandomLine:
       ; THROW               ; ラインを1フレーム当たり1本表示する場合
       LOOP   ld1:
       THROW                 ; 1フレーム当たり30本表示する場合はここ
       ; WAIT                ; ここのコメントを取ると線は書きかえられない
       BRA    LINEDEMO:
       STPALL                ; 意味はないがプロセスの区切りを明確に

; ---------------------------------------------------
;   ランダムな位置にラインを表示
; ---------------------------------------------------
 RandomLine:
       LOAD   R2   16
       RANDOM RZ   R2    ; color
       LOAD   R2   640
       RANDOM RX   R2    ; x0
       RANDOM RH   R2    ; x1
       LOAD   R2   480
       RANDOM RY   R2    ; y0
       RANDOM RP   R2    ; y1
       GRLINE
       RETURN
;<-------------- ここまで

この例では,LINEDEMO: と STR_DEMO: は無限ループとなっています. ループ中に THROW, NOOP, WAIT のうちの1つは必須です.リスト中で コメントアウトされている行を変えて効果を試してみて下さい.


[INDEX] [J3Wリファレンス]
ご意見・ご感想は,水谷 純 <mizutani.jun@nifty.ne.jp> まで.