第3回 物体の形状定義と表示
3D アニメーションに関する連載にもかかわ

しょう。J3Wではすべての面には向きがあり、そこで図1の立方体を図3のようにデフォル

らず言語の解説ばかりでしたが、今回は物体の表からは見えますが裏からは見えない（透明）メします。通常の遠近法とは逆に遠くを大きく形状定義と表示という 3D CG らしい部分を説という性質があります。これは陰に隠れて見え描いています。このように立方体を描くとすべ明します。

ない部分の処理（陰面処理）で、裏から面を見ての頂点が見えます。上下左右の面C、E、D、えなくする（背面消去）と面に関する処理が半

Bに右手をあてて小指の根元から爪に向かう方分になり表示が速くなるためです。また、J3W

向に頂点をたどることで正しく面を定義できまが使っている「塗りつぶし法」という 3D レン

す。例えば面 D は 8-7-6-5（最初の頂点は 8、7、

ダリングで最も単純な（だが速い）方法でも面6、5 のどれでも良い）と決めることは簡単での前後関係が破綻しにくくなります。

す。さて、見えない面Fも親指を紙面奥に向け■物体の形状J3W には 3D モデラー（GUI で物体を作成するプログラム）がありません。従って、頂点座標と多角形を構成する頂点番号を指定して物体

図 1 のような立方体があるとします。8 個のの形状を作成する必要があります。非常に面倒

頂点に 1 から8 の番号を付けます。すべての頂れば2-1-5-6のように、2次元の図を使って頂点を指定することができます。

なようですが、J3Wでは物体をプログラムで作点座標を決めてから 6 個の面（図中の ABC とこの方法は、立方体に限らず三角柱でも6角成できるため、基本となるいろいろな形状の物

裏側の DEF）を定義する必要があります。面錐でも同じようにして面を定義できます。この体（プリミティブ）を作成するためのライブラを定義するには面を表から見て左回りに頂点を方法をマスターすると J3W に付属するソース

リ関数を用意しています。

指定します。「表から見て左回り」では裏側のの頂点定義のコメントの意味が理解できると思面や上下の面が分かりにくくなりますが、これいます。私自身すべてのサンプルをこの方法でにはコツがあります。

作成しています。3D CGを扱うアプリケーショ

例えば、 j 3 w - 6 4 3 / j 3 c _ s c r i p t / l i b /ssolid.j3c では立方体と4角錐（ピラミッド）を定義する関数があります。同じディレクトリ

図2は右手を親指を立てて握り、面の外側にンのほとんどがマウスで簡単に物体を作成できの xsolid.j3c や zsolid.j3c には3、4、6、8

親指を向けた状態を示しています。このとき親るようになっていますが、複数の物体の相対的角柱や角錐、それらを組み合わせた任意の大き指をどちらに向けても小指（4 本の指とも同じな大きさをキチンと指定するには、物体の設計

さの形状を作成できるようにライブラリ関数がですが）の指先に向かって左回りになります。

図を紙に書いた方が近道であると思います。紙用意されています。revolutn.j3cは任意の回

図 2 では 1-4-8-5（4-8-5-1 でも同じ）と頂点の順に設計図を描く場合に以上の手法を意識してい転体（球や楕円体、N 角柱など）を作成できる番を決めることができます。実際に図1でも各れば、「3Dモデラーがなければ3Dは不可能」とようになっています。revolutn.j3cで使って面の頂点の順番を指定してみてください。

は思いません。でも、あれば楽になるような気いる継承の機能は次回以降で解説する予定です

どうですか？ A、B、Cの面の頂点順序は簡が、それまでにJ3Cのプログラム例を読んで予単に決めることができると思います。しかし裏習することをお勧めします。
J3C言語による形状の定義の前に、J3Wにお側には見えない頂点番号 6 の頂点があります。

もチョットします(^^;。

■頂点の指定頭で思い描いて裏側の面の頂点を指定するのはける、頂点と面（多角形）の関係を見ておきま

つらいものです。

【図 1】

【図 2】

J3W では、物体は多角形（面）の集まりで構【図 3】2001.11 Linux Japan57

【リスト 1】

DefPoint(100, 100, 200);【リスト 3】インスタンスの動作例

ClearRegisters(); // RX,RY,RZ,RH,RP,RB に 0 を代入
SetPosition();// ワールド座標系の原点に配置【リスト 2】

RX=100; RY=100; RZ=200; Point();【図 4】下がZ）に配置します。クラスごとに重力を設

Plane 組み込み関数では、図5のように配列に定できますが、重力は物体の姿勢に関係なくワー面に関する情報を設定して、Plane（配列名）

ルド座標系の下方向（Z が正の方向）に働きまを実行します。色、頂点数、頂点番号を変数です。地上の建物のような運動しない物体の場合

実行時に指定することができるようになります

は、その局所座標系を、次の命令でワールド座（リスト 5）。

標系の原点に配置することで、局所座標系とワー頂点番号に負の値を使用すると親の頂点を指ルド座標系を一致させることも可能です（リス定することができます。階層構造の物体間に面ト 3）。

を貼って接続できます。親の頂点番号の指定に回転や移動は局所座標系の座標軸に沿って実は VertexRelative 関数の影響はなく、オブ行されるため、ワールド座標系とは別に、物体

ジェクトごとに0から始まる頂点番号に単にマの回転の中心を局所座標系の原点として形状をイナス符号を付けて指定します。親の頂点番号定義すると良いでしょう。J3Wで使用している

0 は指定できません（負にならないため）。

座標系は航空力学で使用される NED 系（X：
成されますが、多角形を定義するには頂点を指North「前」、Y：East「右」、Z：Down「下」）で定しなければなりません。頂点は空間内の位置

3次元グラフィックでよく使われる座標系とはを使って1つ1つ指定します。頂点の位置は、地異なりますが、地上の建造物のように広がりの面の色は、0-31 の番号で指定します。色番

面に立って前がX、右がY、下がZ という座標系

ある空間では高さ情報を最後に持つ座標系のほ号が 0-15 の場合は、面と光源と視点の角度にを使って指定します。図 1 と図 3 では最も小さ

うが読みやすいと思います。 座標値は符号付き

よって、面の明るさが変化（シェーディング）

い頂点番号は 1 となっていますが、インスタン

32 ビット整数の範囲（± 20 億）が可能です。

します。色の指定が16-31の場合は光源や視点の位置に関係なく、常に同じ明るさで表示され、スで最初に定義される頂点番号は0となります。
頂点を定義するにはDefPoint()かPoint()■面の定義

発光する物体の表現や、地面のように視点の位置で明るさが変化すると不自然な場合に使いま組み込み関数を使います。リスト1の形で座標す。表1に色番号と色の対応の初期値を示しま値を定数式で指定するか、リスト2のようにレ面（多角形）は、「面の色番号、頂点数、頂ジスタ変数経由で値を指定します。プログラム

点の数の頂点番号」を指定することで定義しま

す。 色番号と実際の色との対応はSetColor（色

作成時に座標が決まっている場合にはDefPoint、す。すでに見てきたように面には表と裏があり、番号）という組み込み関数で変更できます。色

実行時まで分からない（計算で頂点座標を求め区別するために、頂点番号の指定には順序を考番号に対応する色は、RX-RBのレジスタ変数でる）場合は Point のように使い分けます。

慮する必要があります。

指定します（表 2）。SetColor はグラフィック
モードの時（GraphMode 実行後）に実行します。

頂点の位置を指定するための座標には、図4面を定義する組み込み関数にはDefPlaneとの座標系を使用します。すべての物体はそれぞPlane があります。DefPlane の引数は、式にれ自分の向いている方向を基準として、前がX、「物体」の面の色を指定し、続いて頂点数と頂右が Y、下が Z の増加する方向です。回転は Z

点番号を定数で設定します。面を構成する多角

軸回りの回転（右を向く）をヘッド回転、 Y軸

形は必ず凸多角形でなければなりません。へこ

回りの回転（上を向く）をピッチ回転、X 軸回んだ形状の多角形は分割して、凸多角形で指定

光源で変化する色番号

りの回転（首を右に傾ける）をバンク回転と呼してください。頂点数個の頂点番号を渡すため、

0

濃灰

16

黒

びます。

パラメータ数は可変となります（リスト4）
。パ

1

青

17

青

ラメータの頂点番号の数が、指定した「物体」

2

緑

18

緑

の頂点数と異なる場合の動作は不定です。

3

水色

19

水色

4

赤

20

赤

5

うす紫

21

うす紫

6

黄

22

黄

7

白

23

白

8

濃灰

24

濃灰

頂点座標はインスタンスごと（物体ごと）に1つ存在する局所座標系で指定します。その局
所座標系を SetPosition 関数を使って、ワー

DefPlane関数では、頂点番号を定数で指定

ルド座標系（北を向いて立ち、北がX、東がY、しなければなりませんが、引数を配列で与える【図 5】【リスト 4】

DefPlane( 式 , 頂点数 , 1, 2, 3, 4, 5 )【リスト 5】

Vertex[0] = color;
Vertex[1] = 3;
Vertex[2] = j + i;
Vertex[3] = j + i + 1;
Vertex[4] = j + i + 2;
Plane(Vertex);

58

■面の色

J3W for Linux 入門講座// 色// 頂点数// 頂点 0// 頂点 1// 頂点 2

RX-RZを０に設定すると光源の影響を受けない色にできます。
【表 1】色番号と色の対応の初期値変化しない色番号

9

濃青

25

濃青

10

濃緑

26

濃緑

11

うす緑

27

うす緑

12

茶

28

茶

13

ピンク

29

ピンク

14

オレンジ

30

オレンジ

15

クリーム

31

クリーム

【リスト 6】■頂点番号の相対指定// 垂直尾翼
VertexRelative();
DefPoint( -10, -1, -50); //0
DefPoint(-300, -1, -50); //1
DefPoint(-300, -1, -90); //2
DefPoint(-390, -1,-240); //3
DefPoint(-305, -1,-240); //4
DefPoint(-100, -1, -90); //5
DefPlane(color, 4, 0, 1, 2, 5);
DefPlane(color, 4, 2, 3, 4, 5);
VertexRelative();
DefPoint( -10, 1, -50); //0
DefPoint(-300, 1, -50); //1
DefPoint(-300, 1, -90); //2
DefPoint(-390, 1, -240); //3
DefPoint(-305, 1, -240); //4
DefPoint(-100, 1, -90); //5
DefPlane(color, 4, 5, 2, 1, 0);
DefPlane(color, 4, 5, 4, 3, 2);

少し複雑な物体では、頂点が多くなり、面を登録する時の頂点番号を間違えないようにすることが難しくなってきます。例えばフライトシ
ミュレータのサンプルに登場するファルコンは180の頂点からなる1つの物体となっています。
J3W 付属の j3c_script/flight/falcon02.

j3cで形状を定義していますが、垂直尾翼の定義部分を見てみましょう（リスト 6）。
ファルコンの垂直尾翼の右側の面と左側の面を定義していますが、どちらの面も頂点番号は5までしか使っていません。これらの頂点が180の頂点の何番目か筆者も数えたことはありません。VertexRelative()関数を実行した直後に定義した頂点は、その後の面定義では0番目の

4-- 3
/
5
2
0----------1
/

4-- 3
/
5
2
0----------1/

頂点として指定できます。物体を構成する1つの部品の最初で VertexRelative() 関数を実行すれば、その部品の最初の頂点番号を0として参照することができます。物体全体の頂点数を意識しないで部品ごとに頂点の追加や削除が可能となります。

■物体の大きさ3D アニメーションの主役は物体ですが、物体の大きさを決めないと「頂点座標を定義」することができません。J3Wでは空間の大きさは【リスト 7】tetra.j3cclass Tetrahedron {int shape(int color) {NewObject(4, 4);// オブジェクトの生成 4 頂点 4 面
DefPoint(0, 0, -283); // 頂点 0 三角形の頂点座標を登録
DefPoint(200, 0,0); // 頂点 1
DefPoint(-100,-173,0); // 頂点 2
DefPoint(-100, 173,0); // 頂点 3
DefPlane(color,3, 0, 1, 2); // 面の定義 表から見て左回りに指定
DefPlane(color+1, 3, 0, 3, 1);
DefPlane(color+2, 3, 3, 0, 2);
DefPlane(color+3, 3, 3, 2, 1);}± 20 億の整数で表現できます。OpenGL や
DirectXのように浮動小数点の数値を扱うことはできませんが、有効桁数はむしろ大きくなります。数値の単位は何でも構いません。例えば1cm を最小単位とすると± 2 万 km の範囲を表現できます。これなら、地球表面（約 5億平方km）をカバーすることができてしまいます。
フライトシミュレータのように広い範囲を扱いたい場合には1cmを最小単位として考えれば良いと思います。人体モデルや家具、建物を考int INIT() {shape(9);ClearRegisters();
SetPosition();}// 形状定義// RX - RB に 0 を代入// 初期位置と角度の設定

int RUN() {RotHead(6000, 2880);
RotPitch(6000, 2880);
DeleteObject();
Stop();}// 6 秒間で 360 度回転// 6 秒間で 360 度回転// 形状を削除// 全インスタンス終了

int EVENT() {}える場合には 1mm が扱いやすい単位になると}思います。単位はオングストロームでも光年でclass main {int INIT() {new(Tetrahedron, 50);// 正 4 面体のインスタンスの生成
NewObject(0, 0);// 視点用の物体の生成
ClearRegisters();// RX - RB に 0 を代入
RX = -1000;// 位置の指定 10m 後方
SetPosition();// 位置と角度を視点に設定
See();// このオブジェクトが見る
BackgroundColor(0x422); // 背景色を設定
GraphMode();// グラフィックウインドウを開く
Zoom(1);// 視野角 53 度(2 倍ズーム)}

も自由に決めることができますが、それでは画面に表示される大きさはどうなるのでしょうか？
図 6 は視点から 100 の距離にある長さ 200 のパイプを見た場合を示しています。もし最小単位を 1m と考えるならば、100m の距離にある
長さ200mのパイプとなり、最小単位をナノメー【表 2】
光源から照明された場合の色RX 拡散光 赤成分 ( 0 - 255 )RY 拡散光 緑成分 ( 0 - 255 )RZ 拡散光 青成分 ( 0 - 255 )光源から照明されない場合の色RH 周辺光 赤成分 ( 0 - 255 )RP 周辺光 緑成分 ( 0 - 255 )RB 周辺光 青成分 ( 0 - 255 )int RUN() {Wait();}// 何もしない

int EVENT() {}}2001.11 Linux Japan59

【図 6】

トルと考えれば（本物の）CPU内部の配線の幅

タンスを new() 組み込

順に付けられます。 DefPlane組み込み関数でとして扱うことができます。また、組み込み関み関数を使って生成しています。これでクラス

面の色、頂点数、頂点番号列を指定することで面を定義します。

数のZoomをZoom(1)と指定することで、デフォ

Tetrahedron のインスタンスは実行を始めまルトの視野角 90 度を約 53 度に変更できます。

す。2つのインスタンスが同時に動き始めます

視点と物体の位置は図8の関係にあります。正Zoom(1)の状態では2倍に拡大（ズーム）され、が、文章では視点となる main クラス（のイン4 面体の中心はワールド座標系の原点にありま

例えば距離1000の大きさ1000の物体が画面いっスタンス）の動作から説明します。

す。J3Wでは視点の位置や角度が自由に変更でぱいに表示されます。

視点には頂点も面も必要ないので頂点と面のきるため、物体を「見失ってしまう」ことがあ

図 7 は図 6 の状態が表示された画面を示しま

数を 0 として見えない物体を生成しています。

ります。慣れるまでは、図 8のように、物体をす。つまり物体の大きさは視点からの距離だけ

ただし見えなくても、 SetPosition で設定さワールド座標系の原点に配置し、視点は物体ので決まるため、単位の決め方には依存しません。

れた位置と角度の情報を持ちます。

大きさ程度の距離を後ろにさがり（X が負の位

カメラで人物を写す場合と山を撮る場合を考え

ClearRegisters() は RX、RY、RZ 、RH 、RP、

置）
、角度はすべて 0 にしておくと、「見失ってれば簡単です。太陽も離れているから小さく見

RB をすべて0にする関数です。その後、RXに-何も表示されない」
状況を防ぐことができます。

えます。ただし、視点に近すぎる物体（距離501000 を代入して、ワールド座標(-1000, 0, 0)に4 面体の運動は RotHead(6000，2880)と以内）と、遠すぎる場合（距離4000000）
はクリッ

視点を配置しています。SetPosition には位

RotPitch(6000，2880)で指定しています。この

置座標(RX,RY,RZ) と角度(RH ，RP ，RB) をレ

場合 6 秒間で 360 度ヘッド回転（Z 軸回り）しジスタ変数に設定して呼び出します。すると、た後、6秒間で360度ピッチ回転（Y 軸回り）しSee()を実行したインスタンスから見た光景がて終了します。移動や回転に使う組み込み関数

ウィンドウに表示されます。実際に表示するたで指定する時間は、ミリ秒を単位とします。角

J3W の特徴の 1 つは、3 次元空間に存在する

めには GraphMode 組み込み関数を実行してグ

度は1/8度を単位として、例えば30度は240とすべての物体が「視点になることができる」こラフィックウィンドウを開く必要があります。

なります。移動距離は頂点座標で使う数値と同とです。視点になっている物体から見た3次元

この組み込み関数はどのインスタンスが実行しじ単位を使います。リスト7の回転速度を変更

空間がスクリーンに表示されます。従って、少ても構いませんが、複数のウィンドウを開くこ

して実際に試してください。さらに Up、Forward

なくとも 3 次元空間に「物体」と「物体を見てとはできません。この例では Zoom(1) を実行などの組み込み関数を順次実行することでいろいる物体」が存在する必要があります。

して、視野角を約 53 度に変更しています。物

いろな動きを与えることができます。

ピングによって切り取られて表示されません。

■物体の表示1 つのインスタンスは 1 つの物体になること

体が2倍にズームされ、周辺部の歪みが小さくまた、この記事で説明した方法を使って紙にができます。これにより最低でも、2つのインなります。INITメソッドの仕事は以上です。こ正 4 面体を描いて見てください。DefPoint とスタンスが必要になります。また視点と物体での例では視点は移動しないためRUNメソッドでDefPlane で頂点と面の登録の部分のコードを異なる動作をする場合には、クラスも2つ必要

は終了イベントを待っているだけです。

になります。

60【図 7】

さて、クラス Tetrahedron のインスタンス

リスト 7 では、自動的に生成される main ク

は、INIT メソッドが shape メソッドを呼び出

ラスのインスタンスが空の（形のない）物体をして、NewObject() 組み込み関数を使って形生成し、位置を SetPosition 組み込み関数で状を生成するための準備をします。NewObject()

設定してSee組み込み関数で視点を取得します。

の引数には最大頂点数と最大面数を与えます。

このインスタンスが目となり、2番目のインス

頂点数、面数は実際に使用する数より多くてもタンス（Tetrahedron）は正 4 面体の物体とな

問題ありませんが、少ないとエラーが発生しまります。

す。形状の定義はDefPoint組み込み関数でＸ、

クラス main は自動的に実行される INIT メ

Ｙ、Ｚ座標を指定して1つずつ頂点を登録しま

ソッドの冒頭でクラス Tetrahedron のインスす。頂点番号はオブジェクトごとに0から登録

J3W for Linux 入門講座

【図 8】

実際に書いて、リスト7と比較してみることをJ3W for Linux最新版ソースコードについて

お勧めします。一見すると面倒で読み飛ばした
くなる部分ですが、形を変えたり頂点を追加したりすれば、すぐに慣れてくると思います。

■終わりに

J3W

for

L i n u x の最新版ソースコードているかどうかの確認も忘れず行ってください。も「j3w643.tar.gz」を、本誌付録 CD-ROM に収録しし含まれていない場合は、 . b a s h r c ファイルにています。インストールを行うには、圧縮ファイル「export PATH=/usr/local/bin:$PATH」のようにを展開後、j3w-643ディレクトリに移動します。そパスを追加してください。

の後「make && make strip」と打ち込んでコンパインストールについてさらに詳しい情報を知りた

イルを行います。次にrootユーザーになって「makeい場合には、作業を行う前にJ3W添付のREADME.euc

で最も重要な部分を解説しました。次回は、少install && make clean」とすると、作業は終了

ファイルを確認してください。J3Wに関する詳細な

しずつ異なる多くの物体をコードの再利用によっします。

情報も同梱のドキュメントに含まれています。

物体の形状定義という 3D CG を作成する上て楽にプログラミングできるように、J3C言語（編集部）

コマンドの検索パスに /usr/local/bin が含まれの継承の機能の解説を予定しています。

J3W の内部構造の解説
前回は、物体の形状に関する情報はTPolygonsク

伴って右を向きます。親が動くと子孫すべての位置や角度

物体はすべて 3 次元空間内に存在しています。そラス、移動や回転は TAxis クラスが担当することをが影響を受けるため、頂点の座標は親から順に決定する必の3 次元空間を扱うのが TSpaceh3D クラスです。実

解説しました。TPolygons、 TAxis クラスをまとめ要があります。THObj3Dクラスのすべてのインスタンスは

際にスクリーンに描画するクラスはTScreenの派生て、頂点や面を 1 つの物体として扱うために親物体へのポインタをもっていますが、親がない（NULL）

クラスである ScrnX です。 ScrnX は Xlib を使って直TObject3D クラスがあります。

場合は、その物体はワールド座標系に独立して存在します。

線や多角形を X Window System のウィンドウに描親を持つインスタンスは親の局所座標系に配置されること画します。

■物体の階層構造

で、親の位置や姿勢が子供に反映されるようになります。

次回は、これまで解説したクラスを実際に使った、

J3Wでは階層構造（多関節の物体）を扱うために、

TObject3D を継承して拡張した THObj3D クラス（図小さな3dプログラムを紹介する予定です。
（水谷純）

■空間

A ）が 3 D エ ン ジ ン の ま と め 役 と な っ て い ま す 。

物体を実際にスクリーンに表示する部分は、TSpaceH3D

THObj3Dクラスが物体の形、位置、運動を管理し、座クラスが「レンダリングエンジン」として担当します。

標変換の計算も担当する「ジオメトリックエンジン」

TSpaceH3Dクラスは、3次元空間全体を管理するために次となっています。

のような機能を持っています（図 C）。

例えば人体は多くの関節でできており、ある関節を曲げるとその先の関節の位置が変わります（腕の関節を曲げると手首の関節の位置が変わりますね）。
物体を関節ごとに階層に分けて管理する必要があります。図Bでは非常に簡略化していますが、階層構造の関係の例を示しています。
この図Bでは、人体を構成する個々のパーツが親子関係となっており、上のレベルほど人体の姿勢に大きな影響を与えます。例えば 2 段目の胸のパーツを右にひねることを考えると、頭も腕も胸の動きに【図 A】THObj3D クラス【図 B】階層構造の関係の例

1 3 次元空間に対して物体の登録や削除をする。
2 視点を持つ物体を指定する。
3 視点座標系で表されているポリゴン（多角形）をスクリー
ン の 表 示 範 囲 に 合 わ せ て 切 り 取 る（ ク リ ッ
ピング）。
4 3次元のポリゴンをスクリーンに合わせて2次元に変換する。
5 光源の位置と種類に合わせてポリゴンの色を決定する。
6 視点から遠いポリゴンから描画する。

【図 C】TSpaceH3D クラス

2001.11 Linux Japan

61