JAVA press vol.1 JAVAで3Dプログラム


                                                             村崎 達哉



                               JAVA press Vol.1(技術評論社)


「Javaと3D」

vrml_sgi.jpg mad
SGIのVRMLサイト

1.JavaとVRML

●まえがき

私はSFは好きですが、通という程ではありません。しかしちょっと昔「サイバーパンク」なる言葉が流行っていたのは覚えています。サイバーパンクの小説に出てくるようなサイバー空間と人間の意識の融合といったようなことは、「2001年」のHALよりももっと絵空事のように感じていました。

ところが、インターネットのVRMLの技術を知ったとき、技術の進歩というのは、たいていは連続的に発展していくものだけれど、ときどき複数の異なった技術が融合することで全く新しい段階に飛躍することがあるものだ、と思い知らされました。まさにVRMLの目指すものはリアリティを持った仮想世界をネトワーク上に構築しようとする試みであり、SFに書かれていたことのかなりの部分が現実となりつつあるのです。

しかし、ひところ騒がれた割には、Javaやプッシュ型技術に比べるといまいち注目度は低いような気がします。(プッシュ型もかなり旗色わるいようですけど)技術的には最も未来的でエンターテイメント性も高いというのに、なぜ思うように人気が出ないのでしょう。それはVRMLのサイトに行ってみると、誰でもすぐに気が付くことです。遅い、あまりに遅い。最近のPCは3Dの表示もかなり改善されてきているので表示そのものは我慢に耐えうると思います。もちろんSGI(Silicon Graphics International)のマシンやAlpha NTマシンに比べれば、パーソナルユースのペンチ(Pentium or Pentium II)マシンではちょっと役不足の感もありますが、CPUクロックが333MHzや400MHzになり、最近発表されたインテルのグラフィックチップi740などを積んだマシンを使えばSGIのローエンドマシンと同等程度にパフォーマンスは上がるでしょう。しかし問題はインターネットの帯域幅です。現状のVRML技術はオブジェクトを最初にダウンロードする方式で、これに時間がかかるのですね。ちょっとインタラクティブというには程遠い。サーバとの3Dオブジェクトのやり取りがリアルタイムにできるようになるには、インターネット環境の改善を待つしかありません。

それなら私たちは指を咥えて待っているべきでしょうか。当然この本を買ったあなたはJavaに関心を持っていて、そのうちJavaを使って何かしようと思っているわけですから、世界中にVRMLが普及するまで待つわけにはいきません。JavaとVRML技術を使って、人のできないサイトを作って、自分の技術力をクライアントにアピールしなければなりません。こんな景気の悪い時でも、ハイテクネットワーク企業は積極的に新サービスを企んでいるはずで、JavaやVRMLのエキスパートであるあなたは、きっと高く買われることでしょう。買われるかもしれません。そこできょうは、Javaと3Dの基本を押さえることにします。

●VRML 2.0

2Dする場合には、その出力先としていろんなグラフィックフォーマットがあります。例えばインターネットではGIFやJPEGといったフォーマット、ウインドウズの標準はビットマップです。3Dの場合でもさまざまなフォーマットがあります。昔からCAD分野ではデファクトスタンダードに近いものとして、AutoDesk社のDFXフォーマットやANSIの規格であるIGESなどがあります。しかしこれらのフォーマットは、どちらかといえば異なる3Dシステム間でデータをやり取りするために仕方なく利用されるような性格が強く、基本的にはそれぞれのソフトウェアメーカーがそれぞれ独自のフォーマットを使っていたというのが実状です。

SGIのCosmoPlayer 2.0 MSのInternet Explore 4.0VRMLアドオン ソニーのCommunity Place
SGIのCosmoPlayer 2.0MSのInternet Explore 4.0VRMLアドオンソニーのCommunity

そんな混沌とした状況のところへ華々しくデビューしたのが、VRMLというフォーマットです。WEBで使用されるHTML(Hyper Text Markup Language)と兄弟のような名前が示すとおり、インターネット用に開発された3Dフォーマットです。VRMLはVirtual Reality Modeling Lauguageの略称です。VRMLのプレイヤーの有名どころのには<図3〜5>などがあります。VRMLについては書籍なども多く出回っているので、詳細は説明しませんが、考え方だけを説明することにします。

VRMLはこの数年のインターネットの急成長がなかったら出現しなかったことでしょう。きっとインターネット上で3D仮想空間を構築したいと思ったサイバーパンク世代の3Dグラフィックスのプログラマーが思い付いたに違いありません。実はVRMLは何の予兆もなく処女受胎した訳ではありません。もともとSGIのハイエンドのグラフィックツールキットOpen Inventor用に開発されたivフォーマットを基に、それをインターネット用に改造したのがVRMLです。VRML1.0に関しては、一見してもほとんど違いはありません。改造したというより流用したといった感じです。

VRML 2.0はいくつもの候補の中からソニー、SDSCグループ、SGIらで開発を進めたMoving Woldsを基に1996年8月4日にISO/IEC14772として仕様が確定しました。VRML 1.0とVRML 2.0の違いを上げるなら次のように要約できます。

  1. 拡張された静的なオブジェクト
  2. ルート制御やセンサー機能によるインタラクション
  3. プロトタイプイングで新しいオブジェクトの定義
  4. アニメーションのための補間処理
  5. JavaScriptとJavaによるスクリプティング

さて、Javaでコントロールする方法について説明する前に、VRMLというものを全く知らない人のために、VRML言語の基本について簡単に説明しましょう。今後はSGIのCosmoWold<図6>やパラグラフ社のVirtual Home Space Builder<図7>(後にSGIに買収され、Cosmo HomeSpaceとなる)などのモデラー機能やリンクを張る機能を持った簡単VRMLエディターが続々登場してきますし、既存のCADやCGソフトもVRMLを出力する機能を備えたものが増えてきました。<図8>これからは3Dオブジェクトを手入力する必要性はだいぶ少なくなると思いますが、HTMLの例からいっても最後は手で調整するぐらいの基本知識は持ち合わせたほうがいいと思います。なんでも簡単にはいかないのがコンピュータですからね。行き詰まったときはさらに低レベルまで戻ってチェックするというのがデバッグの王道というものです。

図6.cosmoworld 図7.home_space 図8lightwave.jpg
図6.cosmoworld図7.home_space図8 lightwave

現在のNetscape Navigator 4.0にはCOSMO Player 1.0というプラグインがデフォルトでインストールされるようになっています。Internet Explorer 4.0では、VRMLデータ表示は標準でサポートされています。以前と違ってVRMLを表示するのにプラグインをダウンロードしたりすることは必要なくなってきました。それではVRMLの文書がどんなものか見てみましょう。将来的にはバイナリファイルフォーマットもサポートされる可能性もありますが、Version 1.0、2.0はテキストファイルのみです。

<リスト1> 図9 cube

			

#VRML V2.0 utf8



#最も簡単なVRMLデータ例

#1個の何の変哲もないキューブ

Shape {

	appearance Appearance { 	#概観ノード

		material Material {

			diffuseColor 1. 1. 0

		}

	}

	geometry Cube {				#幾何ノード

    	width  1.0   #SFFloat 幅

    	height 1.0   #SFFloat 高さ

    	depth  2.0   #SFFloat 奥行

	}

}

			

		
cube

の穂ファイルが

#VRML V2.0 utf8

のヘッダより、VRML V2.0のファイルだということが分かります。V1.0のときは以下にあるように書きましたので、いきなり違いが現れました。なお、utf8はユニコードの文字セット(ISO 10646)を表しています。

<リスト2>

#VRML V1.0 ascii



Cube {

    width  1.0   #SFFloat

    height 1.0

    depth  2.0

}

			

それと、昔はCubeを表示するだけなら上記のようにCube {}と書けばよかったのですが、今では幾何ノードを表示するだけでも


Shape {

    geometry      XXXXXX

    appearance    YYYYYY

} 

で表現しなければならなくなりました。ところでCubeのような組み込みタイプのオブジェクトにはどんなものがのでしょうか。Open InventorにはNodeという概念があり、このノードを木構造上に構成したのがシーンとなります。同様にVRML 2.0にも次の9つのノードグループに分けられるノード群が存在します。

これらについて、詳しく知りたければ、VRML Version 2.0の仕様書

http://www.webcity.co.jp/info/andoh/vrml/vrml2.0/

を参照していただくとして、幾何ノードには次のものが

あります。 IndexedLineSetはポリライン、IndexedFaceSetはポリゴンです。ElevationGridは、地形図を表現するときなどに使う格子ポリゴンであり、Extrusionは2次元図形をスイープ(押し出し)して3次元図形を作るオブジェクトでひねり、ねじりを加えたりというような得技もできます。

Open Inventorには自由曲面などもありますが、Version 2.0でも処理速度の問題で外されました。IndexedFaceSetなどがいわゆるポリゴンということになり、ちょっと複雑なモデルなんかは、他のモデラーなどでDXFファイル(AutoCADのフォーマット)でセーブし、VRMLフォーマットに変換してVRMLブラウザに読み込んだりできます。もっとも最近のモデラーではVRMLで出力できるのが常識のようになっていますので、他のモデラーからのインポートはほとんど困らないでしょう。

話はそれましたが、それではもうちょっと複雑なVRMLファイルを見てみましょう。それぞれの行の意味についてはコメントをよく参照して下さい。

<リスト3>

#VRML V2.0 utf8



Shape {

	#概観の設定です。表面の色、質感を定義します。

	appearance Appearance {

		material Material { diffuseColor  .7 0 0 }  #赤、緑、青の成分

	}

	#立方体を定義します。

	geometry Box { size  5 5 1  }

}

	

Group {

	children [



		#TextureSphereを定義します。これについては後述します。

		DEF TextureSphere Transform {   // ----- (A)

			children Shape {

				appearance Appearance {

					#テクスチャマッピング(絵の貼り付け)設定

					texture ImageTexture { url "image1.jpg" } 

				}

				#球を定義します

				geometry Sphere { radius 1 }

			}

		},

		#PlaneTransセンサーを定義します。これについては後述します。

		DEF PlaneTrans PlaneSensor {} // ------ (B)

	]

}

#これについては後述します。

ROUTE PlaneTrans.translation_changed TO TextureSphere.set_translation // -- (C)

		
Plane1 Plane2
図10 plane1図10 plane2

このソースはちょっと複雑です。(A)で出てきた

DEF ノード名 ノード型 { .... }

は複製もとのノードを定義します。例えば、家のオブジェクトを作成するとき同じ形状のドアがいくつもある時は、1個だけDEFして他はUSE文を使ってコピーします。たとえば、


// OriginalCylinderの定義、描画

DEF OriginalCylinder Shape {

	geometry Cylinder {}

}



.....(略)....



// OriginalCylinde再利用

USE OriginalCylinder

といった使い方です。(A)では座標変換ノードTextureSphareを定義して、表示しています。使用はROUTE文で行われています。V

また、(C)では次の構文が使用されています。ルーティングといわれる重要な機能です。


  ROUTE ソースノード名.イベント発信者名 TO ターゲットノード名.イベント受信者名

              (eventOutかexposedField)    (eventInかexposedField)

簡単に説明すると、ソースノードのイベントが発信されて、ターゲットノードがイベントを受信して、何らかのアクションを起こすというのがルーティングです。このルーティングについては、今一つ分かりにくいと思います。私自身も最初ちょっとしっくりいきませんでした。上の例で具体的に見ていきましょう。

(B)でPlaneSensorが定義されています。これは、ドラッグセンサーの一つで、オブジェクトを平面上に固定させるときに使用するセンサーです。この例ではTextureSphareは赤い板の平面の延長上を動くだけです。PlaneSensorのメンバを見てみましょう。

<PlaneSensorのメンバ>


PlaneSensor {

  //フィールドタイプ   型    フィールド名   デフォルト名

    exposedField     SFVec2f minPosition     0 0

    exposedField     SFVec2f maxPosition     -1 -1

    exposedField     SFVec3f offset          0 0 0

    exposedField     SFBool  autoOffset      TRUE



    eventOut         SFBool  isActive        TRUE

    eventOut         SFBool  trackPoint      TRUE

    eventOut         SFBool  translation     TRUE

}

これはVRML 2.0の使用の書き方ですが、最初のタイプと型は大抵省略されて書かれます。しかし、ルーティングを考えるとき重要なのはフィールドタイプです。ここでは出てきませんが、ただのfieldというタイプもあってこれがVRML 1.0における属性フィールドです。それ以外のタイプは2.0で導入されました。

その他にeventIn、evantOut、exposedFieldがあります。まとめますと、

field VRML 1.0と同じ属性フィールド
eventIn イベントを受け取り、自分の値をイベントの値で書きかえる、
イベントの受信者(sink)です
evantOut 自分の値をイベントとして送り出します、
イベントの送信者(source)です
exposedField イベントの送信者でもあり、受信者でもあります

これで上記ROUTE構文の意味が分かると思います。

ROUTE PlaneTrans.translation_changed TO TextureSphere.set_translation

(C)の文はPlaneTransのtranslationが変化するとその値がTextureSphare(Transform)の translationの値に設定されるという意味です。なお、わかりやすくするためにeventOutには_changed(変えられた)を付けたり、eventInにはset_(設定する)を付けてもよいことになっています。

VRML 2.0はこんな感じです。こういう丸とか四角とかいった幾何学図形で単純なロボットぐらいならテキストエディタで編集できるかもしれませんが、ちょっと複雑なも、建築パースとか局面を使った動物などのモデリングはちょっと無理です。3DCGソフトで作成したものを、VRMLコンバータで変換して使用するのが通常のやり方でしょう。しかし、3DCGソフトで格好いい凝ったオブジェクトを作っても、現状では膨大なポリゴンを使った複雑なオブジェクトはデータが巨大になるのでオンライン上で転送、表示するのはちょっとはばかられます。

●オブジェクトをJavaでコントロールする

ここまでの話題はこの本のテーマであるJavaとはあまり関係ありませんでした。それならVRMLとJavaはどんな関係にあるのでしょう。VRML 1.0では、静的に構築された仮想空間を視点を移動することにより、ただウォークスルーするといった使い方しかできませんでした。VRML 2.0では今見てきたように、イベントのハンドリングができるようになりました。しかし、<リスト3>で見たようにセンサーノードを利用したイベントハンドリングではあまり複雑なことはできません。というのはどちらかというとVRMLは3Dの幾何学的要素を定義する言語ですので、これだけで複雑なアニメーションなどを制御するのは土台無理な話です。より複雑なことをさせえようと思ったらスクリプティングの登場となります。スクリプティングにはJavaScriptとJavaが使用できます。JavaScriptの方は端折って、さっそくJavaによるスクリプティングの例を見てみましょう。

今回はNetscape 4.03にCosmoPlayer 2.0をインストールしてWindows NT上で実行してみました。最初、Windows 95のOSR1でやっていたのですが、Netscapeに標準でインストールされているCosmoPlayer 1.0ではJavaはどうも上手く動きませんでした。JavaScriptはOKでした。どうも95ではOSR1ではJavaの動作がおかしいというのは前から気づいていました。ブラウザで「Javaを起動しています」中に固まってしまうことが多いのです。OSR2ではそんなことはないようです。Javaのスクリプティングが上手くいかないのはCosmoPlayer 1.0が悪いのかOSR1が悪いのかまだ見極めていなのですが、結論からいうと<>といえそうです。スレッドの実行を考えてもNTの方がいいと思います。

<リスト4> 図11 bild2.jpg

#VRML V2.0 utf8



#

# クリックすると家が喋ります。

#



// 建物のオブジェクトの定義

Transform{

        children[

        Inline {url "house.wrl"},  // 建物を読み込みます

        DEF TOUCH_ME TouchSensor{}

        ]

}



// サウンドの定義

Sound{

        maxFront 100

        maxBack 100

        source DEF VOICE1 AudioClip{

                loop FALSE

                url "voice1.wav"   // このサウンドファイルを再生します

        }

}



// スクリプトの定義

DEF TALK_SCRIPT Script{

        url "TalkHouse.class"

        eventIn SFTime invoked

        eventOut SFTime startTalking

}



ROUTE TOUCH_ME.touchTime TO TALK_SCRIPT.invoked

ROUTE TALK_SCRIPT.startTalking TO VOICE1.set_startTime



	
 図11 bild

このファイルをブラウザに読み込むと家(といってもギリシャのパルテノン神殿みたいな家ですが)が出てきます。Transformの中でhouse.wrlを読み込んでいるのが分かりますね。サウンドの定義でもvoice1.wavが再生されるだろうということは予想がつきます。

さて、スクリプトの定義のところでこのスクリプトの実態はTalkHouse.classというJavaのクラスであることが分かります。ソースは当然TalkHouse.javaです。更にeventInタイプのinvokedとeventOutタイプのstartTalkingが定義されています。

ルーティングを見てみると家がタッチされるとその時間がTALK_SCRIPTのinvokedにセットされます。また、TALK_SCRIPTのstartTalkingが変化するとその値がVOICE1のstartTimeに設定されます。これでは何が起きるのかまだ分かりません。それではスクリプトの方を見ることにしましょう。<リスト5>

<リスト5>

//

//   TalkHouse.java

// 「クリックすると家がしゃべります」のスクリプト

//



import java.util.*;

import vrml.*;

import vrml.node.*;

import vrml.field.*;



public class TalkHouse extends Script{

    SFTime startTalking;

    

    // 初期化

    public void initialize(){

        // VRML中で定義されたTALK_SCRIPTのeventOutのstartTalkingを取得

        startTalking = (SFTime)getEventOut("startTalking");

    }

    

    // イベントハンドラ

    public void processEvent(Event e){

        if(e.getName().equals("invoked") == true){

            double touchTime = ((ConstSFTime)e.getValue()).getValue();

            

            // しゃべり始める

            startTalking.setValue(touchTime);

        }

    }

}

		

initialize()はVRMLが起動時に、VRML中で定義されたTALK_SCRIPTのeventOutのstartTalkingを取得してその参照を返します。そのフィールドに対応するJavaの適当なクラスに変換します。イベントハンドラprocessEvent()の方はinvokedイベントが来ると、そのイベントが持っている、家がタッチされた時刻をstartTalkingにセットします。すると2番目のルーティングが起動されてAudioClipのstartTimeへセットされます。startTimeは再生のスタート時間なので、現在時刻がstartTimeを過ぎると音のデータの再生が始まります。したがってすぐに再生が始まります。

どうでしょうか、簡単なような難しいような・・・ でも素人にはちょっと無理かも知れません。ここまで来ると、仕事でやるか、遊びでもよっぽど暇な人ぐらいしか、プログラムは無理でしょう。

2. Java 3D

●Java 3D API

java3D

Javaの言語仕様だけを見てもJavaの本当の魅力は理解できません。言語的には簡易C++といったところでしょうか。C++のプログラマなら、ほとんど苦労なく理解できます。むしろ、ポインタが使えなかったり、クラスの定義を複数ファイルに実装できなかったりとかゆいところに手が届かないもどかしさを感じるくらいです。

Javaは言語ですが、従来の言語のように単にプログラムを記述する際の文法というよりもその充実したクラスライブラリ(API)を含めたトータルな開発システムと捉えた方が適切だと思います。おそらくこの本の他の章で見てきたようにJDK 1.1や1.2には数多くのパッケージが存在します。JDK 1.1からUnicodeの対応、AWTの刷新、JDBCやJavaBeans、JNIなど実に多彩なAPIがそろえられました。しかし、これでもWindowsなどの既存のシステムに比べれば、まだまだ追いついたとはいえません。プログラマが実際開発をする上で必要だと思われるAPIが現在も開発途上です。現在JDK 1.2のベータが配布されており、98年春にはリリース予定です。私は個人的にはJava 1.2でようやく一人前になったかなと考えています。今までもJavaのアプリケーションを開発してきた人は多いでしょうが、大抵はプロトタイプだったり、研究用だったりで、商用アプリは厳しいと言うのが現実だったでしょう。それはたとえば、ドラッグアンドドロップを正式にはサポートしていなかったり、日本語フロントエンドなども機能が不十分だったりと、何かとやりくりして開発しなければならなかったからでしょう。そして、ようやく頼れるハイティーンに成長して、もうちょっとで成人だ、というところまで来ているのでしょう。もう、プログラマの皆さん、待つ必要はないようです。

あのコーレルがオフィススウィートの開発をあきらめたり、期待していたNetscapeのJava版ブラウザJavagator(ジャビゲータ、すごい名前)が開発保留したりしたことには、目をふさぎましょう。われわれにはあのロータスのeSuiteがあるではないですか、私はきっとロータスの成功を機会にコーレルもジャビゲータも蘇生してくることを信じています。

JDK 1.2にはわれわれが喉から手が出る程待ち望んでいた、Java Media and Communication APIの一部も含まれる予定です。一部といったのはJava 2D以外は含まれないようです。Java 2DはJava Foundation Class Libralyとして提供されるようです。われわれの待ち望むJava 3DやJava Telephonyは次のJDK 1.2Xか1.3を待たなければなりません。

しかし、Java 3Dの仕様は確定していますので、かなりの情報を入手することが可能です。ここでは、Java 3Dの特徴やプログラムの概略について見て行きましょう。

ところで、Java 3Dがなぜ必要なのでしょうか。3Dを表示するのに今まで説明してきたVRMLがあるじゃないですか。VRMLとJava 3Dはなにがどう違うのでしょうか。一言でいうと<<VRMLは3Dのデータフォーマットから発展してきた技術で、Java 3Dの方は3Dアプリケーションを開発するためのAPI>>といえると思います。VRMLを表示するには、VRMLようのブラウザやプラグインが必要ですし、また、そのウインドウの中でできることはVRML規定されていることだけで、かなり限定されてきます。もちろんスクリプトとしてJavaを組み込めますが、それはあくまでもイベントハンドラとしてでVRMLに従属する形です。たとえばVRMLに付随する技術だけでCADアプリケーションを作ることはまず、無理でしょう。

Java 3Dは3次元のアプリケーションやアプレットを開発するためのAPIだと考えていただければ結構です。Java 3D APIの仕様ははインテル、アップル、SGI、サンの4社の協力で作成されたようです。マイクロソフトは参加してません。

それではjava.media.java3Dパッケージの階層を見てみましょう。


java.media.java3D

                    VirtualUniverse

                    Locale

                    View

                    PhysicalBody

                    PhysicalEnvironment

                    Screen3D

                    Canvas3D (extends awt.Canvas)

                    SceneGraphObject

                            Node

                                    Group

                                    Leaf

                            Appearance

                            Geomoetry

                            Material

                            AuralAttributes

                            TexGen

                            TexImage

                            Texture

                    Transform

VRMLでいうところのノードにあたるのが、SceneGraphObject以下のオブジェクトです。3D仮想空間シーングラフの最上位に位置するのがVritualUniverseでその下にLocaleオブジェクトが定義され、その下に幾つものグループが定義されます。LocaleはVirtualUniverseの中の原点座標位置を設定します。Viewは見えかたを定義し、Screen3D、Canvas3Dが何を表すかは明らかでしょう。これらオブジェクトはクラスとして実装されているので、それぞれに自分自身を操作するための関数群を内包しています。

● Java 3Dのサンプルプログラム

次に簡単なシーングラフを生成するJava 3Dのサンプルプログラムを示します。これによって生成されたシーングラフは<図13>のようになります。プログラムの作成手順は次の通りです。

  1. キャンバスオブジェクトを生成してアプレットパネルに付加します。
  2. シーングラフのルートとしてブランチグループを生成します。
  3. 座標変換オブジェクトを上位に持ったシェープノードを構築します。
  4. 座標変換オブジェクトに回転補完ビヘイビアーを付加します。.
  5. 次の項目を実行するためにユニバースビルダーの関数を呼びます。

    a. シングル高解像度ロケールを持った仮想ユニバースを構築します。

    b. 物理ボディ, 物理環境, ビュープラットフォームを作成します。

    c. ビュープラットフォームのブランチのルートとしてブランチグループを作成します。

    d. ロケールににビュープラットフォームブランチを挿入します。

  6. ユニバースビルダーのロケールにシーングラフブランチを挿入します。

なんせ、まだ実現されていないAPIですのでプログラムは書けても、実行はできませんので実行画面をお見せできないのが残念です。一応紙飛行機を表示するプログラムです。なお、java 3Dの実装系がリリースされたとき、このプログラムが正常に動作することは保証されません。あくまでも概念ということで・・・ 苦しい。

scenegraph

図13

<リスト5>

//

// カラフルな紙飛行機を表示するアップレットプログラム

//



// アプレットのクラス

public class DispPaperPlane extends Applet {



     public BranchGroup createSceneGraph() {



         // ブランチグラフのルートを作成

         BranchGroup objectRoot = new BranchGroup();



         // 座標変換グループを作成、設定する

         TransformGroup objectTrans = new TransformGroup();

         objectTrans.setCapability(

                             TransformGroup.ALLOW_TRANSFORM_WRITE);

         objectRoot.addChild(objectTrans);



         // 紙飛行機のリーフノードを作成し、シーングラフに追加する

         objectTrans.addChild(new PaperPlane().getShape());



         // ビヘイビアーオブジェクトを作成し、回転アニメーションが

         // できるように設定する

         Transform3D yAxis = new Transform3D();

         Alpha rotationAlpha = new Alpha(

                     -1, Alpha.INCREASING_ENABLE,

                     0, 0, 4000, 0, 0, 0, 0, 0);

         RotationInterpolator rotator = new RotationInterpolator(

                     rotationAlpha, objectTrans, yAxis,

                     0.0f, (float) Math.PI*2.0f);

         BoundingSphere bounds =

                 new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

         rotator.setSchedulingBounds(bounds);

         objectTrans.addChild(rotator);



         return objectRoot;

     }



     public DispPaperPlane() {

         // キャンバスの作成

         setLayout(new BorderLayout());

         Canvas3D canvas = new Canvas3D(graphicsConfig);

         add("Center", canvas);



         // シーングラフを作成し、仮想ユニバースにアッタチする

         BranchGroup scene = createSceneGraph();

         UniverseBuilder universe = new UniverseBuilder(canvas);

         universe.addBranchGraph(scene);

     }

}



// 仮想ユニバースのクラス

public class UniverseBuilder extends Object {



     // 3Dキャンバス

     Canvas3D canvas;



     // シーングラフの要素

     VirtualUniverse    universe;

     Locale             locale;

     TransformGroup     vpTrans;

     View               view;



     public UniverseBuilder(Canvas3D c) {

         this.canvas = c;



         // 仮想ユニバースとロケールを作成

         universe = new VirtualUniverse();

         locale = new Locale(universe);



         // 物理ボディを作成

         PhysicalBody body = new PhysicalBody();

         PhysicalEnvironment environment = new PhysicalEnvironment();



         // ビューを作成

         view = new View();

         view.addCanvas3D(c);

         view.setPhysicalBody(body);

         view.setPhysicalEnvironment(environment);



         // ブランチグループを作成

         BranchGroup vpRoot = new BranchGroup();



         // ビュープラットフォームと座標変換グループを作成

         Transform3D t = new Transform3D();

         t.set(new Vector3f(0.0f, 0.0f, 2.0f));

         ViewPlatform vp = new ViewPlatform();

         TransformGroup vpTrans = new TransformGroup(t);



         vpTrans.addChild(vp);

         vpRoot.addChild(vpTrans);



         view.attachViewPlatform(vp);



         // Attach the branch graph to the universe, via the Locale.

         // The scene graph is now live!

         locale.addBranchGraph(vpRoot);

     }



     public void addBranchGraph(BranchGroup bg) {

         locale.addBranchGraph(bg);

     }

}



// 紙飛行機のクラス

public class PaperPlane extends Object {



     private static final float[] verts = {

/* 参考

          0.0f,  0.0f,  0.5f,

         -0.5f,  0.0f, -0.5f,

         -0.1f,  0.1f, -0.5f,

          0.0f, -0.3f, -0.5f,

          0.1f,  0.1f, -0.5f,

          0.5f,  0.0f, -0.5f,

*/

         // 右翼

          0.0f,  0.0f,  0.5f,

         -0.5f,  0.0f, -0.5f,

         -0.1f,  0.1f, -0.5f,

         // 右動体

          0.0f, -0.3f, -0.5f,

         -0.1f,  0.1f, -0.5f,

          0.0f,  0.0f,  0.5f,

         // 左動体

          0.0f, -0.3f, -0.5f,

          0.1f,  0.1f, -0.5f,

          0.0f,  0.0f,  0.5f,

         // 左翼

          0.1f,  0.1f, -0.5f,

          0.5f,  0.0f, -0.5f,

          0.0f,  0.0f,  0.5f,

     };



     private static final float[] colors = {

         // 右翼(赤)

          1.0f, 0.0f, 0.0f,

          1.0f, 0.0f, 0.0f,

          1.0f, 0.0f, 0.0f,

         // 右動体(緑)

          0.0f, 1.0f, 0.0f,

          0.0f, 1.0f, 0.0f,

          0.0f, 1.0f, 0.0f,

         // 左動体(青)

          0.0f, 0.0f, 1.0f,

          0.0f, 0.0f, 1.0f,

          0.0f, 0.0f, 1.0f,

         // 左翼(黄色)

          1.0f, 1.0f, 0.0f,

          1.0f, 1.0f, 0.0f,

          1.0f, 1.0f, 0.0f,

     };



     private Shape3D shape;



     public PaperPlane() {

         TriangleArray plane = new TriangleArray(12,

                         TriangleArray.COORDINATES | TriangleArray.COLOR_3);



         plane.setCoordinates(0, verts);

         plane.setColors(0, colors);



         shape = new Shape3D(plane, new Appearance());

     }



     public Shape3D getShape() {

         return shape;

     }

}



// end of program

	

Open Inventorを知っている人なら、ほとんどそっくりなプログラム方法であることが分かります。であるなら、Open Inventor(C++)−>Java 3D(Java)のコンバータなど作れば売れるでしょうか。最近私は、VB −> JavaというプログラムをObjectTiger<図14>というオンラインショップから購入しました。500ドルぐらいでしたが、米国製ソフトが、買ってすぐ使用できるこのインターネットの世界は、やっぱりすごい、けれど、これからの流通マージンを稼いでいるソフトウェア流通業者にとって地獄のような時代の到来です。

Objtiger

図14 Objtiger

ところで、このプログラムを書く上で調べていてわかったのですが、幾何図形ノードの中にVRMLのような球、ボックス、円錐などといったいわゆるプリミティブはありません。あるのは、点、ライン、ポリゴンだけです。これはプログラマとしてはやりにくいですね。きっとOpenGLのようにこのようなプリミティブを生成するマクロ関数が提供されることになるのでしょう。

● Java 3Dの特徴

プログラムのサンプルを見てきたところでJava 3Dの特徴をまとめてみましょう。

  1. 3D空間を作成するための豊富なオブジェクトセット
  2. 開発効率を向上させるハイレベルなオブジェクト指向プログラミング
  3. VRMLやCADフォーマットなどのランタイムローダに対応可能
  4. シーングラフプログラミングモデル
  5. ハイレベルな抽象化により様々なローレベルAPIに対応(Direct3D, OpenGL, QuickDraw3D)

5については、Windowsの特にゲームなどではDirect3Dが主流ですが、CAD分野などではWindowsでもOpenGLがスタンダードで、米国などでは最近はゲームもOpenGLでやろうというのが流行のようです。Direct3DはWindowsオンリーで論外としても、これから3Dアプリを開発するなら、プラットフォーム依存のより高速性を追求するアプリならOpenGL、「Write once, run anywhere」を指向するならJava 3Dでしょうか。

なお、この原稿を書いている最中にJava 3D 1.1 APIのアナウンスがあり、その実装もJavaOne Developer Conference on March 24, 1998.で入手できるようになるということです。楽しみです。

● 最後に

javasoft

「Javaは実行速度が遅い」、「APIが実用的でない」と批判する人もいますが、それは木を見て森を見ないようなもので、実行速度の問題は高級言語ですからマシン語のように高速になることはなくても、VBやC++程度にチューニングすることは夢ではありません。近いうちに実際そうなると思います。コンパイラ側ではJITやHotSpot技術などで高速化され、また、これから開発されるCPUの多くが何らかの型でバイトコードを高速に実行する仕組みを取り入れることになると思われます。これも、この本のどこかに書いてあると思います。

また、APIが実用的でないという人はJavaSoftのWEBページを見たことがあるのでしょうか。現在開発中あるいはこれから開発されるAPIの豊富さ、そして、その有機的に結び付けられたAPIの構成の美しさを見れば、マイクロソフトの散発的なツールキット群と比較したとき、プログラマならどちらを取るべきかは明白です。もちろんWindowsのAPIには多種多様なものがあり、現時点で商用ベースのプログラムを開発するとしたら、Windows APIやMFCで書くのがベストかもしれません。しかし、マイクロソフトがここまで来るのに何年かかったのでしょう。10年以上かけて漸次発展してきたAPIと、この2、3年で生まれたAPIを同等に比較すること自体不公平ではありませんか。ソフトウェアプロダクトは数年先の市場を意識して開発を進めなければなりません。私には、マイクロソフトのC++ライブラリMFCは、ボーランドがいち早くOWLというクラスライブラリをリリースしたことにより、慌てて急造された拙速気味ライブラリだと思っています。とてもC++のエキスパートが設計したとは思えない仕様で、それを今でも引きずっています。よく言われる<>がそのことを如実に物語っています。それに比べてJava方は、実用的なレベルまで行くのに千里の道を歩んでいるといったところですが、インターネット100%活用することで世界中の頭脳を結集して人類の遺産として設計されています。(ちょっと大袈裟か)だから私はJava派なのです。ついでに言わせてもらうなら、NetPC派ではなくNC派であり、PCの命脈は既に終わっていると考えています。(だってBill GatesはNCなんて使えないといっている端から、NetPCだとかWindows Terminalだとかいっているじゃないですか、これってほとんどNCですよ。)

javastation
前にもどる