雑誌発表後、 HotJava/Java FAQの安藤さんから次の点をご指摘をいただきました。
本文中にはミラーサイトのURLが紹介してあるが、一次配布先を紹介した方が良いのではないか、というものです。
すでにJDKをはじめとするソフトウエアのバージョンが上がっているので
時期的に遅くなったかも知れませんが、本稿で紹介したソフトウエアの一次配布先を書いておきます。
一次配布先が無いものは開発元サイトのダウンロード情報ページを紹介します。
Linux ディストリビューションに依存したもの(RPMファイル)はそのディストリビューションのURLを書きました。
ソフトウエア | ファイル名 | バイト数 | 一次配布先またはダウンロード情報 |
---|---|---|---|
JDK 1.2 pre-v2 | jdk1.2pre-v2.tar.bz2 | 19,532,163 | http://www.blackdown.org/java-linux/mirrors.html |
Java 3D 1.1.1 pre-v1 | java3d1_1_1pre-v1-linux-sdk.tar.bz2 | 2,180,744 | |
Mesa 3.0 | Mesa-3.0-2.i386.rpm | 443,581 | http://www.mesa3d.org/download.html |
Mesa glut 3.0 | Mesa-glut-3.0-2.i386.rpm | 102,429 | |
Mesa開発用ヘッダー | Mesa-devel-3.0-2.i386.rpm | 559,672 | |
Mesa glut開発用ヘッダー | Mesa-glut-devel-3.0-2.i386.rpm | 121,121 | |
Mesaデモ | Mesa-demos-3.0-2.i386.rpm | 1,903,456 | |
kinput2 (Vine 1.0) | kinput2-v2-fix5-alpha7-1.i386.rpm | 151,497 | ftp://ftp.ryukyu.ad.jp/pub/Vine/Vine-1.0/i386/Vine/RPMS/ |
shuJIT | shujit-0.3.10-bin-linux-glibc-jdk12.tar.gz | 60,200 | http://www.shudo.net/jit/dist/ |
JDK 1.2.2のインストールについては、本稿より後に書いた JDK 1.2.2 RC3, Java 3D 1.1.1をKondara MNU/Linuxへインストールする を参照してください。
えんどう やすゆき yasuyuki@javaopen.org (タイムインターメディア)
はじめまして、えんどう やすゆき と申します。勤務先はタイムインターメディアです。本誌では、上司の藤原博文が「Javaとパズルの世界」という連載でお世話になっております。:O)
所属は情報通信サービス部です。インターネット・イントラネット関連のシステム構築やセキュリティーなどを専門とする部署です。私の現在のメインの業務はネットワーク管理と技術調査です。
出来たばかりの会社なので、メイン以外の業務もやらなければならない場合があります。以前 CG の仕事をやったことが災い(?)したのか、最近では地図情報システムの地層3次元表示部分を Java 3D で開発しました。
今年の春から「はじめての Java 3D」という書籍の執筆を始めました。この号が出る頃には書店に並んでいるとうれしいと思っています。出版社は技術評論社です。(宣伝^^;)
私は当初、Windows 95/98, NT で Java 3D を使っていました。(以後 Windows 95/98, NT を Win32 と表記することがあります)
1998年に Java 2 (JDK 1.2) と共に正式リリースされた Java 3D は、当初 Solaris (SPARC CPU), Windows 95/98, NT (Intel x86 CPU) のみに対応していました。
その後 JDK 1.2 の Linux への移植が開始され、Java Media API が Linux に対応することが Sun から正式にアナウンスされました。現在 Java 3D 1.1.1 pre-v1 が公開されています。
Linux 用の JDK 1.2 を使ってみて驚いたのはそのパフォーマンスです。現在1台のコンピューターを Windows 98 と Linux のデュアル・ブートで使用していますが、Linux の方が明かにパフォーマンスが良いです。たとえば、JDK 付属の Java2D のデモを実行してみるとはっきりわかります。
Java 3D に関しても、Java の実行環境としては Linux に明かに分があります。ただし、3D 表示はグラフィックス・ボードのハードウエア・アクセラレーションなどに依存します。現在 OpenGL ボードの多くは Windows NT に対応しているので、この点は Windows NT が有利かもしれません。
Solaris, Win32 以外では、SGI (シリコングラフィックス), HP (ヒューレット・パッカード) が Sun と Java 3D のライセンス契約を結びました。今年行われた SIGGRAPH '99 LA では、SGI, HP のワークステーションで Java 3D が動いていたそうです。
また、9月には SGI IRIX用の Java 3D がリリースされました。
Linux用のJDK 1.2, Java 3Dのインストール方法を説明します。
これを書いている時点 (1999年9月上旬) では、Java 3DはIntel x86対応の Version 1.1.1 pre-v1がリリースされています。
Linux用のJava 3Dの稼働環境は次の通りです。
Linux 用の Java 3D は、OpenGL 互換のフリーの 3D グラフィクス API である Mesa 上で稼働します。
Linux用のJDK, Java 3Dの最新バージョンについては下記を参照してください。
また、既知のバグについての情報は必ず参照してください。
http://www.blackdown.org/java-linux/jdk1.2-status/known-bugs.html
以下では、次のソフトウエアのインストールを説明して行きます。
えんどう は Vine Linux 1.0beta でインストールしました。Vine Linux 1.1 でもほぼ同様にインストールできると思います。
インストールが終ったら、次のトピックスをとりあげます。
Linux用のJDK 1.2を入手します。
これを書いている時点では、JDK 1.2のバージョンはpre-release 2です。
えんどう は下記のミラーサーバーからダウンロードしました。
ftp://ftp.lab.kdd.co.jp/Linux/java-linux/JDK-1.2/i386/pre-v2/glibc2.0/jdk1.2pre-v2.tar.bz2
えんどう がダウンロードしたのは、以下のファイル名とファイルサイズのものです。
jdk1.2pre-v2.tar.bz2 19,532,163バイト
JDK 1.2 は glibc2 (glibc 2.0 以上) で動作します。
JDK 1.2 pre-v2 には、glibc 2.0 対応版と、glibc 2.1 対応版があるので注意してください。
glibc2に対応したLinuxディストリビューションとしては、Red Hat 5.2, Debian GNU/Linux 2.1などがあります。
えんどう はRed Hat 5.2をベースにした日本語対応のディストリビューションであるVine Linux 1.0 betaを使用しました。
なお、Red Hat 6.0 をベースにした Turbo Linux 4.0 には JDK 1.2 pre-v1 がインストール済みです。Turbo Linux 4.0 に付属の JDK 1.2 では、後述のフォント・エラーにも対処済みのようです。
手軽に JDK 1.2 を楽しみたい方は Turbo Linux 4.0 を試されるのも良いかもしれません。
(ディストリビューションの構成が "Small is beautiful" ではないので Turbo Linux は えんどう の好みに合いませんでした。旧パシフィック・ハイテック社時代に「Linux」の商標権を一方的に主張したことがありましたが、このときも良い印象を受けませんでした)
Vine Linuxに関しては、下記のサイトをご参照ください。
JDK 1.2をホームディレクトリーにダウンロードしてあるものとします。
インストール作業はrootで行います。
rootとしてログインするか、suコマンドでrootユーザーに切替えて作業してください。
ここではJDK 1.2を/usr/local配下にインストールしています。
次の例では、jdk1.2pre-v1.tar.bz2 をホーム・ディレクトリー $HOME にダウンロードしています。
$ su Password: # cd /usr/local # bzip2 -cd $HOME/jdk1.2pre-v2.tar.bz2 | tar xf -
えんどう が使用する Vine Linux 1.0 beta には bzip2 が含まれていますが、標準インストール時には bzip2 がインストールされないようです。Vine Linux 1.1 では、Vine のインストールで bzip2 もインストールされると思います。
bzip2については下記サイトをご参照ください。
http://sourceware.cygnus.com/bzip2/index.html
JDK 1.2を動作させるには、環境変数PATHにJDKのbinディレクトリーが含まれている必要があります。
bashでは次のように設定します。JDK 1.2 のインストール・ディレクトリーが例と異なる場合は適宜変更してください。
$ export PATH=/usr/local/jdk1.2/bin:$PATH
コマンドラインからjavaを実行してみましょう。
$ java -version java version "1.2" Classic VM (build Linux_JDK_1.2_pre-release-v2, native threads, sunwjit)
今度は、SwingのサンプルであるSwingSetを実行してみます。
$ cd /usr/local/jdk1.2/demo/jfc/SwingSet/ $ appletviewer SwingSetApplet.html appletviewer SwingSetApplet.html Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific] Font specified in font.properties not found [--zapf dingbats-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific]
メニューのフォントが文字化けしていますが、いちおう実行できています。
前項の例で発生していた zapf dingbats
のフォントエラーを解消する方法は、Known bugs with JDK 1.2 port http://www.blackdown.org/java-linux/jdk1.2-status/known-bugs.html にあります。
http://www.gimp.org/fonts.html から、zapf dingbats
を含む PostScript フォントを入手してください。
日本語フォントを使いたい場合、これだけでは不十分です。JDK 1.2 での日本語フォントの環境設定については、安松一樹さんの下記の投稿がとても役立ちます。
http://java-house.etl.go.jp/ml/archive/j-h-b/024378.html
安松さんの例の通りに日本語 TrueType フォントをインストールした場合、投稿の後半部分に記載されている font.properties
ファイルがそのまま使用できます。
JFC Swing 上で kinput2 を使用する場合、kinput2 のバージョンによっては日本語入力ができない場合があります。
えんどう は次の RPM をダウンロードしてインストールしました。
えんどう がダウンロードしたのは、以下のファイル名とファイル容量のものです。
kinput2-v2-fix5-alpha7-1.i386.rpm 151,497バイト
JDK 1.2 には JIT コンパイラー sunwjit が含まれています。
Known bugs with JDK 1.2 port http://www.blackdown.org/java-linux/jdk1.2-status/known-bugs.html によると、sunwjit を使用すると out of memory などの問題が発生することがあるようです。
Known bugs with JDK 1.2 port では、JIT コンパイラーを使用しないようにしてこの問題を回避する、という方法が紹介されています。
JIT コンパイラーを使用しないようにするには次の2つの方法があります。
JAVA_COMPLIER=NONE
を追加する-Djava.compiler=NONE
を追加する-J-Djava.compiler=NONE
としてください)別の対処方法として、sunwjit
以外の JIT コンパイラーを使用する方法があります。
えんどう は、首藤一幸さんによるフリーの JIT コンパイラー shuJIT をインストールしました。shuJIT の最新情報については次のサイトを参照してください。
http://www.shudo.net/jit/index-j.html
えんどう は次の場所から shuJIT をダウンロードしました。
http://www.shudo.net/jit/dist/shujit-0.3.10-bin-linux-glibc-jdk12.tar.gz
えんどう がダウンロードしたのは以下のファイル名とファイル容量のものです。
shujit-0.3.10-bin-linux-glibc-jdk12.tar.gz 60,200バイト
上記ファイルを展開すると、カレントディレクトリー配下に以下のディレクトリーとファイルが作成されます。
$ tar xvfz shujit-0.3.10-bin-linux-glibc-jdk12.tar.gz shujit/README shujit/GPL.txt shujit/libshujit.so
shuJIT のインストール方法については、README
を必ず参照してください。
えんどう は次の方法でインストールしました。
$ cd shujit $ su Password: # cp libshujit.so /usr/local/jdk1.2/jre/lib/i386/.
shuJIT を使うには次の2つの方法があります。
JAVA_COMPLIER=shujit
を追加する-Djava.compiler=shujit
を追加する-J-Djava.compiler=shujit
としてください)shuJIT の実行を確認してみましょう。
$ java -Djava.compiler=shujit -version shuJIT for Sun JVM/IA-32 Copyright 1998,1999 by SHUDO Kazuyuki java version "1.2" Classic VM (build Linux_JDK_1.2_pre-release-v2, native threads, shujit)
えんどう は .bash_profiles
で JAVA_COMPLIER=shujit
を指定しています。
9月27日に、Borland (INPRISE) から Linux 用の JIT コンパイラー JBuilder Java 2 Just-In-Time Compiler for Linux がリリースされました。JBuilder のために開発されたもので、かなり高速なようです。
http://www.borland.com/jbuilder/linux
からダウンロードできます。ただし残念なことに、オープンソースではないようです。
JDK 1.2 pre-v2 では標準で native thread が使用されます。Known bugs with JDK 1.2 port http://www.blackdown.org/java-linux/jdk1.2-status/known-bugs.html には、native thread 使用時の次のような問題点が報告されています。ガベージ・コレクションが動作しない、JFileChooser
でデッドロックが発生する、などです。
native thread の使用を止め、gneen thread を使うことで、このような問題を回避できるようです。
green thread を使うには次の2つの方法があります。
THREADS_FLAG=green
を追加する-green
を追加する-green
を追加してください)native thread に関する問題点は、Linux 用の JDK 1.2 の正式リリースまでには解消されるのではないか、というのが えんどう の予想です。
LinuxでJava 3Dを動かすためには、OpenGLの互換APIであるMesaが必要です。
えんどう はMesaを下記からダウンロードしました。
ftp://ftp.lab.kdd.co.jp/Linux/packages/RedHat/redhat/powertools/5.2/i386/Mesa-3.0-2.i386.rpm
ftp://ftp.lab.kdd.co.jp/Linux/packages/RedHat/redhat/powertools/5.2/i386/Mesa-glut-3.0-2.i386.rpm
ftp://ftp.lab.kdd.co.jp/Linux/packages/RedHat/redhat/powertools/5.2/i386/Mesa-devel-3.0-2.i386.rpm
ftp://ftp.lab.kdd.co.jp/Linux/packages/RedHat/redhat/powertools/5.2/i386/Mesa-glut-devel-3.0-2.i386.rpm
ftp://ftp.lab.kdd.co.jp/Linux/packages/RedHat/redhat/powertools/5.2/i386/Mesa-demos-3.0-2.i386.rpm
えんどう がダウンロードしたのは以下のファイル名とファイルサイズのものです。
Mesa-3.0-2.i386.rpm | 443,581バイト | // Mesa 3.0.2 |
Mesa-glut-3.0-2.i386.rpm | 102,429バイト | // Mesa glut 3.0.2 |
Mesa-devel-3.0-2.i386.rpm | 559,672バイト | // Mesa開発用ヘッダーファイル |
Mesa-glut-devel-3.0-2.i386.rpm | 121,121バイト | // Mesa glut開発用ヘッダーファイル |
Mesa-demos-3.0-2.i386.rpm | 1,903,456バイト | // Mesaデモ |
Mesaをインストールします。
$ su Password: # rpm -i Mesa-3.0-2.i386.rpm # rpm -i Mesa-glut-3.0-2.i386.rpm # rpm -i Mesa-devel-3.0-2.i386.rpm # rpm -i Mesa-glut-devel-3.0-2.i386.rpm # rpm -i Mesa-demos-3.0-2.i386.rpm
Mesaの動作テストをしてみましょう。
Mesaのデモを実行してみます。
$ cd /usr/lib/Mesa-3.0/demos/ $ ls Makefile gears morph3d.c reflect texcyl Makefile.cygnus gears.c multiext reflect.c texcyl.c bounce girl.rgb multiext.c reflect.rgb texobj bounce.c glinfo multitex renormal texobj.c clearspd glinfo.c multitex.c renormal.c trispd clearspd.c glutfx osdemo spectex trispd.c descrip.mms glutfx.c osdemo.c spectex.c winpos drawpix isosurf paltex stex3d winpos.c drawpix.c isosurf.c paltex.c stex3d.c gamma isosurf.dat pointblast tessdemo gamma.c morph3d pointblast.c tessdemo.c $ ./morph3d Morph 3D - Shows morphing platonic polyhedra Author: Marcelo Fernandes Vianna (vianna@cat.cbpf.br) [1] - Tetrahedron [2] - Hexahedron (Cube) [3] - Octahedron [4] - Dodecahedron [5] - Icosahedron [SPACE] - Toggle colored faces [RETURN] - Toggle smooth/flat shading [ESC] - Quit
Java 3D も面白いですが、C で OpenGL (Mesa) プログラミングも面白いと思います。OpenGL プログラミングについては次の書籍を参考にしてください。
書名: OpenGL プログラミングガイド (第2版) OpenGL バ−ジョン 1.1 対応オフィシャルガイド ISBN: 479529710X 著者: OpenGL ARB (Aachitecture Review Board) 出版社: アジソン・ウェスレイ・パブリッシャ−ズ・(星雲社刊) 本体価格: ¥12,000-
グラフィックス・ボードのハードウエア・アクセラレーションがあると、OpenGL, Mesa などのグラフィックス・パフォーマンスは劇的に向上します。
Mesa 環境でのグラフィックス・ボードのハードウエア・アクセラレーションの対応状況については、Mesa のオフィシャル・サイト http://www.mesa3d.org/ を参照してください。
たとえば現時点では、ftp://ftp.mesa3d.org/mesa/misc/nVidia/ に nVidia 対応のドライバーが登録されています。
3dfx Voodoo ボードへの対応状況は http://www-hmw.caribel.pisa.it/fxmesa/index.shtml にあります。
Windows NT に比べると数は多くありませんが、例えば nVidia は今後積極的に Linux にコミットして行くのではないかと予想しています。
XFree86 の次期バージョンである 4.0 では、Mesa, GLX (X-Winod System の OpenGL 拡張) が XFree86 に取り込まれることになるようです。たとえば pre 4.0 snapshot である、3.9.16 のリリースノート http://www.xfree86.org/snapshots/3.9.16/RELNOTES2.html#11 には次のような記述があります。
2.9. GLX とダイレクト・レンダリング・インフラストラクチャー(DRI) Precision Insight 社は、Red Hat と SGI の協力を受けて、 X11 window での 3D レンダリングの ための GLX 拡張の統合を提供しました。 3D レンダリングのコアになるコンポーネントは Mesa ライブラリーです。 SGI は拡張フレームワークのソースをオープンライセンスの下にリリースしました。 これらは 3D ライブラリーとウインドウシステムの融合を真に提供します。 Precision Insight 社はこれらのコンポーネントを XFree86 の X Server に統合し、 ダイレクトレンダリングのためのインフラストラクチャー (DRI) を追加します。 ダイレクトレンダリングは3Dデータをグラフィクスハードウエアに ダイレクトにシェーディングするための高度に最適化されたパスです。 このリリースは、GMX2000グラフィックカードのための、 アクセラレートされたダイレクトレンダリングのシンプルな実装をdemonstrateします。 将来のリリースでは幅広い3D性能を持つグラフィックディバイスの上で、 ハードウエアアクセラレートされたダイレクトレンダリングが広範にサポートされるでしょう。
XFree86 での GLX のハードウエア・アクセラレーションについては、SGI の以下のページが参考になります。
http://reality.sgi.com/ripperda_engr/glx/
Linux の 3D グラフィック環境はますます充実するのではないかと思います。
Linux用Java 3Dは、これを書いている時点ではpre-v1 (Intel x86)が公開されています。
えんどう は下記からダウンロードしました。
ftp://ftp.lab.kdd.co.jp/Linux/java-linux/java3d/1.1.1/i386/java3d1_1_1pre-v1-linux-sdk.tar.bz2
えんどう がダウンロードしたのは次のファイル名とファイルサイズのものです。
java3d1_1_1pre-v1-linux-sdk_tar.bz2 2,180,744バイト
以下の例では、ホームディレクトリー $HOME にダウンロードしました。
このファイルをJDKのインストールディレクトリーに展開します。
$ su Password: # cd /usr/local # bzip2 -dc $HOME/java3d1_1_1pre-v1-linux-sdk_tar.bz2 | tar xvf - jdk1.2/ jdk1.2/jre/ jdk1.2/jre/lib/ jdk1.2/jre/lib/i386/ jdk1.2/jre/lib/i386/libJ3D.so jdk1.2/jre/lib/i386/libj3daudio.so jdk1.2/jre/lib/ext/ jdk1.2/jre/lib/ext/vecmath.jar jdk1.2/jre/lib/ext/j3dcore.jar jdk1.2/jre/lib/ext/j3daudio.jar jdk1.2/jre/lib/ext/j3dutils.jar jdk1.2/demo/ jdk1.2/demo/java3d/ jdk1.2/demo/java3d/Appearance/ jdk1.2/demo/java3d/Appearance/AppearanceTest.java jdk1.2/demo/java3d/Appearance/AppearanceTest.class jdk1.2/demo/java3d/Appearance/Tetrahedron.java jdk1.2/demo/java3d/Appearance/Tetrahedron.class jdk1.2/demo/java3d/AppearanceMixed/ jdk1.2/demo/java3d/AppearanceMixed/AppearanceMixed.java jdk1.2/demo/java3d/AppearanceMixed/AppearanceMixed.class jdk1.2/demo/java3d/AppearanceMixed/AppearanceMixed$MyCanvas3D.class jdk1.2/demo/java3d/AppearanceMixed/Tetrahedron.java jdk1.2/demo/java3d/AppearanceMixed/Tetrahedron.class jdk1.2/demo/java3d/AWT_Interaction/ jdk1.2/demo/java3d/AWT_Interaction/AWTInteraction.java jdk1.2/demo/java3d/AWT_Interaction/AWTInteraction.class jdk1.2/demo/java3d/Billboard/ jdk1.2/demo/java3d/Billboard/Bboard.java jdk1.2/demo/java3d/Billboard/Bboard.class jdk1.2/demo/java3d/Billboard/MouseRotateY.java jdk1.2/demo/java3d/Billboard/MouseRotateY.class jdk1.2/demo/java3d/ConicWorld/ jdk1.2/demo/java3d/ConicWorld/ConicWorld.java jdk1.2/demo/java3d/ConicWorld/ConicWorld.class jdk1.2/demo/java3d/ConicWorld/FlipCylinder.java jdk1.2/demo/java3d/ConicWorld/FlipCylinder.class jdk1.2/demo/java3d/ConicWorld/README jdk1.2/demo/java3d/ConicWorld/SimpleCylinder.java jdk1.2/demo/java3d/ConicWorld/SimpleCylinder.class jdk1.2/demo/java3d/ConicWorld/TexturedCone.java jdk1.2/demo/java3d/ConicWorld/TexturedCone.class jdk1.2/demo/java3d/ConicWorld/TexturedSphere.java jdk1.2/demo/java3d/ConicWorld/TexturedSphere.class jdk1.2/demo/java3d/FourByFour/ jdk1.2/demo/java3d/FourByFour/BigCube.java jdk1.2/demo/java3d/FourByFour/BigCube.class jdk1.2/demo/java3d/FourByFour/Board.java jdk1.2/demo/java3d/FourByFour/Board.class jdk1.2/demo/java3d/FourByFour/Canvas2D.java jdk1.2/demo/java3d/FourByFour/Canvas2D.class jdk1.2/demo/java3d/FourByFour/Cube.java jdk1.2/demo/java3d/FourByFour/Cube.class jdk1.2/demo/java3d/FourByFour/Cylinder.java jdk1.2/demo/java3d/FourByFour/Cylinder.class jdk1.2/demo/java3d/FourByFour/FourByFour.java jdk1.2/demo/java3d/FourByFour/FourByFour.class jdk1.2/demo/java3d/FourByFour/FourByFour$killAdapter.class jdk1.2/demo/java3d/FourByFour/ID.java jdk1.2/demo/java3d/FourByFour/ID.class jdk1.2/demo/java3d/FourByFour/PickDragBehavior.java jdk1.2/demo/java3d/FourByFour/PickDragBehavior.class jdk1.2/demo/java3d/FourByFour/Poles.java jdk1.2/demo/java3d/FourByFour/Poles.class jdk1.2/demo/java3d/FourByFour/Positions.java jdk1.2/demo/java3d/FourByFour/Positions.class jdk1.2/demo/java3d/FourByFour/README jdk1.2/demo/java3d/FourByFour/fbf.html jdk1.2/demo/java3d/FourByFour/instructions.txt jdk1.2/demo/java3d/FourByFour/scores.txt jdk1.2/demo/java3d/GearTest/ jdk1.2/demo/java3d/GearTest/Gear.java jdk1.2/demo/java3d/GearTest/Gear.class jdk1.2/demo/java3d/GearTest/GearBox.java jdk1.2/demo/java3d/GearTest/GearBox.class jdk1.2/demo/java3d/GearTest/GearTest.java jdk1.2/demo/java3d/GearTest/GearTest.class jdk1.2/demo/java3d/GearTest/Shaft.java jdk1.2/demo/java3d/GearTest/Shaft.class jdk1.2/demo/java3d/GearTest/SpurGear.java jdk1.2/demo/java3d/GearTest/SpurGear.class jdk1.2/demo/java3d/GearTest/SpurGearThinBody.java jdk1.2/demo/java3d/GearTest/SpurGearThinBody.class jdk1.2/demo/java3d/HelloUniverse/ jdk1.2/demo/java3d/HelloUniverse/HelloUniverse.html jdk1.2/demo/java3d/HelloUniverse/HelloUniverse.java jdk1.2/demo/java3d/HelloUniverse/HelloUniverse.class jdk1.2/demo/java3d/Lightwave/ jdk1.2/demo/java3d/Lightwave/README.txt jdk1.2/demo/java3d/Lightwave/Viewer.java jdk1.2/demo/java3d/Lightwave/Viewer.class jdk1.2/demo/java3d/Lightwave/ballcone.lws jdk1.2/demo/java3d/Lightwave/greenball.lwo jdk1.2/demo/java3d/Lightwave/redcone.lwo jdk1.2/demo/java3d/LOD/ jdk1.2/demo/java3d/LOD/LOD.class jdk1.2/demo/java3d/LOD/LOD.java jdk1.2/demo/java3d/Morphing/ jdk1.2/demo/java3d/Morphing/ColorCube.java jdk1.2/demo/java3d/Morphing/ColorCube.class jdk1.2/demo/java3d/Morphing/ColorPyramidDown.java jdk1.2/demo/java3d/Morphing/ColorPyramidDown.class jdk1.2/demo/java3d/Morphing/ColorPyramidUp.java jdk1.2/demo/java3d/Morphing/ColorPyramidUp.class jdk1.2/demo/java3d/Morphing/Morphing.java jdk1.2/demo/java3d/Morphing/Morphing.class jdk1.2/demo/java3d/Morphing/MorphingBehavior.java jdk1.2/demo/java3d/Morphing/MorphingBehavior.class jdk1.2/demo/java3d/Morphing/Pyramid2Cube.java jdk1.2/demo/java3d/Morphing/Pyramid2Cube.class jdk1.2/demo/java3d/Morphing/hand1.obj jdk1.2/demo/java3d/Morphing/hand2.obj jdk1.2/demo/java3d/Morphing/hand3.obj jdk1.2/demo/java3d/ObjLoad/ jdk1.2/demo/java3d/ObjLoad/ObjLoad.java jdk1.2/demo/java3d/ObjLoad/ObjLoad.class jdk1.2/demo/java3d/PackageInfo/ jdk1.2/demo/java3d/PackageInfo/PackageInfo.java jdk1.2/demo/java3d/PackageInfo/PackageInfo.class jdk1.2/demo/java3d/PickTest/ jdk1.2/demo/java3d/PickTest/ColorCube.java jdk1.2/demo/java3d/PickTest/ColorCube.class jdk1.2/demo/java3d/PickTest/ColorPyramidDown.java jdk1.2/demo/java3d/PickTest/ColorPyramidDown.class jdk1.2/demo/java3d/PickTest/ColorPyramidUp.java jdk1.2/demo/java3d/PickTest/ColorPyramidUp.class jdk1.2/demo/java3d/PickTest/CubeIQA.java jdk1.2/demo/java3d/PickTest/CubeIQA.class jdk1.2/demo/java3d/PickTest/GullCG.java jdk1.2/demo/java3d/PickTest/GullCG.class jdk1.2/demo/java3d/PickTest/BoltCG.java jdk1.2/demo/java3d/PickTest/BoltCG.class jdk1.2/demo/java3d/PickTest/CubeQA.java jdk1.2/demo/java3d/PickTest/CubeQA.class jdk1.2/demo/java3d/PickTest/IcosahedronITSA.java jdk1.2/demo/java3d/PickTest/IcosahedronITSA.class jdk1.2/demo/java3d/PickTest/IcosahedronTSA.java jdk1.2/demo/java3d/PickTest/IcosahedronTSA.class jdk1.2/demo/java3d/PickTest/OctahedronITFA.java jdk1.2/demo/java3d/PickTest/OctahedronITFA.class jdk1.2/demo/java3d/PickTest/OctahedronTFA.java jdk1.2/demo/java3d/PickTest/OctahedronTFA.class jdk1.2/demo/java3d/PickTest/TetrahedronITA.java jdk1.2/demo/java3d/PickTest/TetrahedronITA.class jdk1.2/demo/java3d/PickTest/TetrahedronTA.java jdk1.2/demo/java3d/PickTest/TetrahedronTA.class jdk1.2/demo/java3d/PickTest/MorphingBehavior.java jdk1.2/demo/java3d/PickTest/MorphingBehavior.class jdk1.2/demo/java3d/PickTest/PickTestBounds.html jdk1.2/demo/java3d/PickTest/PickTestBounds.java jdk1.2/demo/java3d/PickTest/PickTestBounds.class jdk1.2/demo/java3d/PickTest/PickTestGeometry.html jdk1.2/demo/java3d/PickTest/PickTestGeometry.java jdk1.2/demo/java3d/PickTest/PickTestGeometry.class jdk1.2/demo/java3d/PickText3D/ jdk1.2/demo/java3d/PickText3D/PickText3DBounds.java jdk1.2/demo/java3d/PickText3D/PickText3DBounds.class jdk1.2/demo/java3d/PickText3D/PickText3DGeometry.java jdk1.2/demo/java3d/PickText3D/PickText3DGeometry.class jdk1.2/demo/java3d/PlatformGeometry/ jdk1.2/demo/java3d/PlatformGeometry/SimpleGeometry.java jdk1.2/demo/java3d/PlatformGeometry/SimpleGeometry.class jdk1.2/demo/java3d/PureImmediate/ jdk1.2/demo/java3d/PureImmediate/PureImmediate.html jdk1.2/demo/java3d/PureImmediate/PureImmediate.java jdk1.2/demo/java3d/PureImmediate/PureImmediate.class jdk1.2/demo/java3d/ReadRaster/ jdk1.2/demo/java3d/ReadRaster/ReadRaster.java jdk1.2/demo/java3d/ReadRaster/ReadRaster.class jdk1.2/demo/java3d/ReadRaster/myCanvas3D.class jdk1.2/demo/java3d/ReadRaster/myRotationInterpolator.class jdk1.2/demo/java3d/Sound/ jdk1.2/demo/java3d/Sound/SimplerSound.java jdk1.2/demo/java3d/Sound/SimplerSound.class jdk1.2/demo/java3d/Sound/SimpleSounds.java jdk1.2/demo/java3d/Sound/SimpleSounds.class jdk1.2/demo/java3d/Sound/MoveAppBoundingLeaf.java jdk1.2/demo/java3d/Sound/MoveAppBoundingLeaf.class jdk1.2/demo/java3d/Sound/ReverberateSound.java jdk1.2/demo/java3d/Sound/ReverberateSound.class jdk1.2/demo/java3d/Sound/SimpleSoundsBehavior.java jdk1.2/demo/java3d/Sound/SimpleSoundsBehavior.class jdk1.2/demo/java3d/Sound/AudioBehaviorMoveOne.java jdk1.2/demo/java3d/Sound/AudioBehaviorMoveOne.class jdk1.2/demo/java3d/Sound/AudioReverberate.java jdk1.2/demo/java3d/Sound/AudioReverberate.class jdk1.2/demo/java3d/Sound/hello_universe.au jdk1.2/demo/java3d/Sound/README.release jdk1.2/demo/java3d/Sound/roar.au jdk1.2/demo/java3d/Sound/techno_machine.au jdk1.2/demo/java3d/SphereMotion/ jdk1.2/demo/java3d/SphereMotion/SphereMotion.html jdk1.2/demo/java3d/SphereMotion/SphereMotion.java jdk1.2/demo/java3d/SphereMotion/SphereMotion.class jdk1.2/demo/java3d/SplineAnim/ jdk1.2/demo/java3d/SplineAnim/SplineAnim.java jdk1.2/demo/java3d/SplineAnim/SplineAnim.class jdk1.2/demo/java3d/Text2D/ jdk1.2/demo/java3d/Text2D/MoverBehavior.java jdk1.2/demo/java3d/Text2D/MoverBehavior.class jdk1.2/demo/java3d/Text2D/Text2DTest.java jdk1.2/demo/java3d/Text2D/Text2DTest.class jdk1.2/demo/java3d/Text3D/ jdk1.2/demo/java3d/Text3D/Text3DLoad.java jdk1.2/demo/java3d/Text3D/Text3DLoad.class jdk1.2/demo/java3d/TextureTest/ jdk1.2/demo/java3d/TextureTest/TextureImage.java jdk1.2/demo/java3d/TextureTest/TextureImage.class jdk1.2/demo/java3d/TickTockCollision/ jdk1.2/demo/java3d/TickTockCollision/Box.java jdk1.2/demo/java3d/TickTockCollision/Box.class jdk1.2/demo/java3d/TickTockCollision/CollisionDetector.java jdk1.2/demo/java3d/TickTockCollision/CollisionDetector.class jdk1.2/demo/java3d/TickTockCollision/TickTockCollision.html jdk1.2/demo/java3d/TickTockCollision/TickTockCollision.java jdk1.2/demo/java3d/TickTockCollision/TickTockCollision.class jdk1.2/demo/java3d/TickTockPicking/ jdk1.2/demo/java3d/TickTockPicking/Cube.java jdk1.2/demo/java3d/TickTockPicking/Cube.class jdk1.2/demo/java3d/TickTockPicking/PickHighlightBehavior.java jdk1.2/demo/java3d/TickTockPicking/PickHighlightBehavior.class jdk1.2/demo/java3d/TickTockPicking/Tetrahedron.java jdk1.2/demo/java3d/TickTockPicking/Tetrahedron.class jdk1.2/demo/java3d/TickTockPicking/TickTockPicking.java jdk1.2/demo/java3d/TickTockPicking/TickTockPicking.class jdk1.2/demo/java3d/VirtualInputDevice/ jdk1.2/demo/java3d/VirtualInputDevice/ButtonPositionControls.class jdk1.2/demo/java3d/VirtualInputDevice/ButtonPositionControls.java jdk1.2/demo/java3d/VirtualInputDevice/HelloUniverse.class jdk1.2/demo/java3d/VirtualInputDevice/HelloUniverse.java jdk1.2/demo/java3d/VirtualInputDevice/PositionControls.class jdk1.2/demo/java3d/VirtualInputDevice/PositionControls.java jdk1.2/demo/java3d/VirtualInputDevice/RotationControls.class jdk1.2/demo/java3d/VirtualInputDevice/RotationControls.java jdk1.2/demo/java3d/VirtualInputDevice/SensorBehavior.class jdk1.2/demo/java3d/VirtualInputDevice/SensorBehavior.java jdk1.2/demo/java3d/VirtualInputDevice/VirtualInputDevice.class jdk1.2/demo/java3d/VirtualInputDevice/VirtualInputDevice.java jdk1.2/demo/java3d/VirtualInputDevice/WheelControls.class jdk1.2/demo/java3d/VirtualInputDevice/WheelControls.java jdk1.2/demo/java3d/geometry/ jdk1.2/demo/java3d/geometry/p51_mustang.obj jdk1.2/demo/java3d/geometry/galleon.obj jdk1.2/demo/java3d/images/ jdk1.2/demo/java3d/images/apimage.jpg jdk1.2/demo/java3d/images/bg.jpg jdk1.2/demo/java3d/images/earth.jpg jdk1.2/demo/java3d/images/stone.jpg jdk1.2/demo/java3d/images/ttimage.jpg jdk1.2/java3d-utils-src.jar jdk1.2/README.Java3D-jdk jdk1.2/README.Java3D.linux jdk1.2/LICENSE.Java3D
Java 3Dのデモを実行してみます。
$ cd /usr/local/jdk1.2/demo/java3d/HelloUniverse/ $ java HelloUniverse
Win32 では、ガベージコレクションのときアニメーションが一瞬止まって見えるという現象がありましたが、Linux ではこの現象はほとんど気になりません。
Linux用のJava 3Dの完成度はかなり高いと思います。
Linux での Java 3D プログラミングは、Win32 と特に変わる点はありません。これは、"Write once, view anywhere" という Java 3D のスローガンの通りです。
ただし、現時点では Win32 環境の Java 3D が未対応の機能があります。3次元テクスチャーです。
javax.media.j3d.Texture3D
は3次元テクスチャーのためのクラスですが、OpenGL 1.1 が3次元テクスチャーに未対応なため、Win32 環境では Texture3D
は動作しません。
Solaris の OpenGL 1.1.1 や、Linux での Mesa 3.0.2 では独自の拡張が行われているため Texture3D
が動作します。(Java3Djp メーリングリストで動作報告がありました)
Mesa 3.0.2 には、3次元テクスチャーのサンプル /usr/lib/Mesa-3.0/demos/stex3d.c
が付属しています。
3次元テクスチャーとはどういうものでしょうか。
2次元テクスチャーは「1枚の絵」と考えてください。テクスチャーをポリゴンに張り付けるのにはテクスチャー座標というものを使用します。テクスチャーは 0.0〜1.0
の範囲の2次元テクスチャー座標 s, t
の間に引き延ばされ (または縮められ) る、と思ってください。s
は右方向、t
は上方向が正方向(プラス方向)になります。
ポリゴンの各頂点にテクスチャー座標 (s, t)
を設定し、ポリゴンにテクスチャーをマッピングします。
3次元テクスチャーは「複数枚の重なった絵」と考えてください。3次元のテクスチャー座標は s, t
に加えて r
座標を持ちます。r
は奥行き(深さ)方向が正方向になります。
たとえば、木の年輪を考えてください。年輪は木の中で同心円の円柱のように重なっています。この木を任意の形に掘り出すと、木彫りの彫刻の表面には年輪の模様が描かれます。
年輪のような同心円状の絵が複数重なった3次元テクスチャーを作成したとします。任意の形状の物体にこのテクスチャーを適用すると、物体の表面には木彫りの彫刻の表面のような年輪状の模様が描かれることになります。
3次元テクスチャーは、ポリゴンの頂点に (s, t, r)
で表現されるテクスチャー座標を適用し、テクスチャーをポリゴンにマッピングします。
サンプル・プログラムの実行例を見てください。
このサンプルでは、com.sun.j3d.utils.behaviors.pickig
パッケージを使って、マウスの左/
中/右ボタンで回転/ズーム/移動ができるようになっています。
年輪のような3次元テクスチャーを作成し、年輪の色を深さに応じて変化させています。また、通常のテクスチャーは年輪を真上から見たような方向になるため、javax.media.j3d.TextureAttributes
を使って X軸を回転軸にテクスチャーを 90°回転させています。ウインドウの下部の TextField
に x, y, z, 回転角
を入力して "RotTex"
ボタンを押すと、テクスチャーを回転させることができます。
javax.media.j3d.TexCoordGeneration
でテクスチャー座標を生成していますが、テクスチャー座標生成モードが EYE_LINEAR
なので、物体を回転させても3次元テクスチャーは回転しません。テクスチャー座標の生成モードは、ウインドウ上部の Choice
で変更できます。モードは次の通りです。
OBJECT_LINEAR // オブジェクト座標に従う EYE_LINEAR // 視線座標に従う SPHERE_MAP // 球体反射マッピングを使用する
SHPERE_MAP
は魚眼レンズで撮影されたようなテクスチャーを必要とします。初期状態ではポリゴンの面が描画されています。ウインドウ上部の Choice
を使って、ポリゴンの辺の描画や、ポリゴンの頂点の描画に切替えることができます。
POLYGON_FILL // 面を描画 POLYGON_LINE // 辺を描画 POLYGON_POINT // 頂点を描画
初期状態ではポリゴンの裏面は描画されません。ウインドウ上部の Choice
を使って、表面を描画しない、両方の面を描画する、などのモードに切替えることができます。
CULL_BACK // 裏面を描画しない CULL_FRONT // 表面を描画しない CULL_NONE // 表面も裏面も描画する
条件をいろいろ変更して試してみてください。このサンプルのソースコードは次の通りです。
Texture3DTest.java1 // Java 3D Test Applet 2 // Texture3DTest.java 3 // Copyright (c) 1999 ENDO Yasuyuki 4 // mailto:yasuyuki@javaopen.org 5 // http://www.javaopen.org/j3dbook/index.html 6 7 import java.applet.*; 8 import java.awt.*; 9 import java.awt.event.*; 10 import java.awt.image.*; 11 import java.text.*; 12 import javax.media.j3d.*; 13 import javax.vecmath.*; 14 import com.sun.j3d.utils.applet.MainFrame; 15 import com.sun.j3d.utils.universe.SimpleUniverse; 16 import com.sun.j3d.utils.geometry.Box; 17 import com.sun.j3d.utils.geometry.Cone; 18 import com.sun.j3d.utils.geometry.Cylinder; 19 import com.sun.j3d.utils.geometry.Sphere; 20 import com.sun.j3d.utils.image.TextureLoader; 21 import com.sun.j3d.utils.behaviors.picking.PickRotateBehavior; 22 import com.sun.j3d.utils.behaviors.picking.PickTranslateBehavior; 23 import com.sun.j3d.utils.behaviors.picking.PickZoomBehavior; 24 25 public class Texture3DTest extends Applet { 26 private Canvas3D canvas_ = null; 27 private SimpleUniverse universe_ = null; 28 private BranchGroup scene_ = null; 29 private Texture texture_ = null; 30 private TextureAttributes txattr_ = null; 31 private TexCoordGeneration texgen_ = null; 32 private PolygonAttributes pattr_ = null; 33 34 private boolean isStandalone = false; 35 36 public Texture3DTest() { 37 this(false); 38 } 39 40 public Texture3DTest(boolean isStandalone) { 41 this.isStandalone = isStandalone; 42 43 this.setLayout(new BorderLayout()); 44 45 Panel uppanel = new Panel(); 46 this.add(uppanel, "North"); 47 48 Choice genchoice = new Choice(); 49 genchoice.add("OBJECT_LIENEAR"); 50 genchoice.add("EYE_LIENEAR"); 51 genchoice.add("SPHERE_MAP"); 52 genchoice.select(1);//EYE_LINEAR 53 genchoice.addItemListener( new ItemListener() { 54 public void itemStateChanged(ItemEvent e) { 55 String item = (String)e.getItem(); 56 int mode = texgen_.getGenMode(); 57 if (item.equals("OBJECT_LIENEAR")) { 58 mode = TexCoordGeneration.OBJECT_LINEAR; 59 } else if (item.equals("EYE_LIENEAR")) { 60 mode = TexCoordGeneration.EYE_LINEAR; 61 } else if (item.equals("SPHERE_MAP")) { 62 mode = TexCoordGeneration.SPHERE_MAP; 63 } 64 universe_.getLocale().removeBranchGraph(scene_); 65 texgen_.setGenMode(mode); 66 universe_.addBranchGraph(scene_); 67 } 68 }); 69 uppanel.add(genchoice); 70 71 Choice polchoice = new Choice(); 72 polchoice.add("POLYGON_FILL"); 73 polchoice.add("POLYGON_LINE"); 74 polchoice.add("POLYGON_POINT"); 75 polchoice.addItemListener( new ItemListener() { 76 public void itemStateChanged(ItemEvent e) { 77 String item = (String)e.getItem(); 78 if (item.equals("POLYGON_FILL")) { 79 pattr_.setPolygonMode(PolygonAttributes.POLYGON_FILL); 80 } else if (item.equals("POLYGON_LINE")) { 81 pattr_.setPolygonMode(PolygonAttributes.POLYGON_LINE); 82 } else if (item.equals("POLYGON_POINT")) { 83 pattr_.setPolygonMode(PolygonAttributes.POLYGON_POINT); 84 } 85 } 86 }); 87 uppanel.add(polchoice); 88 89 Choice culchoice = new Choice(); 90 culchoice.add("CULL_BACK"); 91 culchoice.add("CULL_FRONT"); 92 culchoice.add("CULL_NONE"); 93 culchoice.addItemListener( new ItemListener() { 94 public void itemStateChanged(ItemEvent e) { 95 String item = (String)e.getItem(); 96 if (item.equals("CULL_BACK")) { 97 pattr_.setCullFace(PolygonAttributes.CULL_BACK); 98 } else if (item.equals("CULL_FRONT")) { 99 pattr_.setCullFace(PolygonAttributes.CULL_FRONT); 100 } else if (item.equals("CULL_NONE")) { 101 pattr_.setCullFace(PolygonAttributes.CULL_NONE); 102 } 103 } 104 }); 105 uppanel.add(culchoice); 106 107 Panel downpanel = new Panel(); 108 this.add(downpanel, "South"); 109 110 downpanel.add( new Label("TexRot - X") ); 111 final TextField xfield = new TextField("1.0"); 112 downpanel.add(xfield); 113 114 downpanel.add( new Label("Y") ); 115 final TextField yfield = new TextField("0.0"); 116 downpanel.add(yfield); 117 118 downpanel.add( new Label("Z") ); 119 final TextField zfield = new TextField("0.0"); 120 downpanel.add(zfield); 121 122 downpanel.add( new Label("A") ); 123 final TextField afield = new TextField("0.5"); 124 downpanel.add( new Label("* PI") ); 125 downpanel.add(afield); 126 127 Button rbutton = new Button("RotTex"); 128 rbutton.addActionListener( new ActionListener() { 129 public void actionPerformed(ActionEvent e) { 130 try { 131 float x = Float.parseFloat(xfield.getText()); 132 float y = Float.parseFloat(yfield.getText()); 133 float z = Float.parseFloat(zfield.getText()); 134 float a = Float.parseFloat(afield.getText()); 135 AxisAngle4f ax = new AxisAngle4f(x, y, z, a * (float)Math.PI); 136 Transform3D t3d = new Transform3D(); 137 t3d.setRotation(ax); 138 txattr_.setTextureTransform(t3d); 139 } catch (NumberFormatException ex) {} 140 } 141 } ); 142 downpanel.add(rbutton); 143 } 144 145 public void init() { 146 GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); 147 canvas_ = new Canvas3D(config); 148 this.add("Center", canvas_); 149 150 universe_ = new SimpleUniverse(canvas_); 151 //universe_.getViewer().getView().setDepthBufferFreezeTransparent(false); 152 universe_.getViewingPlatform().setNominalViewingTransform(); 153 154 scene_ = createSceneGraph(); 155 //scene_.compile(); 156 157 universe_.addBranchGraph(scene_); 158 } 159 160 private BranchGroup createSceneGraph() { 161 BranchGroup root = new BranchGroup(); 162 root.setCapability(BranchGroup.ALLOW_DETACH); 163 164 Background bg = new Background(new Color3f(0.5f, 0.5f, 0.5f)); 165 bg.setApplicationBounds(new BoundingSphere(new Point3d(), 100.0)); 166 root.addChild(bg); 167 168 TransformGroup objTrans = new TransformGroup(); 169 170 BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0);171 172 PickRotateBehavior rotater = 173 new PickRotateBehavior(root, canvas_, bounds); 174 root.addChild(rotater); 175 176 PickTranslateBehavior translater = 177 new PickTranslateBehavior(root, canvas_, bounds); 178 root.addChild(translater); 179 180 PickZoomBehavior zoomer = 181 new PickZoomBehavior(root, canvas_, bounds); 182 root.addChild(zoomer); 183 184 double[] vertices = { -0.8, -0.8, 0.0, 185 -0.8, 0.8, 0.0, 186 -0.4, -0.8, 0.0, 187 -0.4, 0.8, 0.0, 188 0.0, -0.8, 0.0, 189 0.0, 0.8, 0.0, 190 0.4, -0.8, 0.0, 191 0.4, 0.8, 0.0, 192 0.8, -0.8, 0.0, 193 0.8, 0.8, 0.0, 194 -0.8, -0.8, 0.0, 195 0.8, -0.8, 0.0, 196 -0.8, -0.4, 0.0, 197 0.8, -0.4, 0.0, 198 -0.8, 0.0, 0.0, 199 0.8, 0.0, 0.0, 200 -0.8, 0.4, 0.0, 201 0.8, 0.4, 0.0, 202 -0.8, 0.8, 0.0, 203 0.8, 0.8, 0.0 }; 204 205 LineArray geom = new LineArray( vertices.length, GeometryArray.COORDINATES); 206 geom.setCoordinates(0, vertices); 207 Shape3D grid = new Shape3D(geom); 208 objTrans.addChild(grid); 209 210 Appearance ap = createAppearance(); 211 212 Transform3D bt3d = new Transform3D(); 213 bt3d.set(new Vector3d(-0.4, 0.4, 0.0)); 214 TransformGroup btrans = new TransformGroup(bt3d); 215 btrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 216 btrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 217 btrans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); 218 btrans.addChild( new Box(0.25f, 0.25f, 0.25f, 0, ap) ); 219 objTrans.addChild(btrans); 220 221 Transform3D cyt3d = new Transform3D(); 222 cyt3d.set(new Vector3d(-0.4, -0.4, 0.0)); 223 TransformGroup cytrans = new TransformGroup(cyt3d); 224 cytrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 225 cytrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 226 cytrans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); 227 cytrans.addChild( new Cylinder(0.3f, 0.6f, 0, ap) ); 228 objTrans.addChild(cytrans); 229 230 Transform3D cnt3d = new Transform3D(); 231 cnt3d.set(new Vector3d(0.4, 0.4, 0.0)); 232 TransformGroup cntrans = new TransformGroup(cnt3d); 233 cntrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 234 cntrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 235 cntrans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); 236 cntrans.addChild( new Cone(0.3f, 0.6f, 0, ap) ); 237 objTrans.addChild(cntrans); 238 239 Transform3D st3d = new Transform3D(); 240 st3d.set(new Vector3d(0.4, -0.4, 0.0)); 241 TransformGroup strans = new TransformGroup(st3d); 242 strans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 243 strans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 244 strans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); 245 strans.addChild( new Sphere(0.3f, 0, ap) ); 246 objTrans.addChild(strans); 247 248 root.addChild(objTrans); 249 250 return root; 251 } 252 253 private Appearance createAppearance() { 254 Appearance app = new Appearance(); 255 256 BufferedImage[] bimages = new BufferedImage[64]; 257 258 float dh = 1.0f / 64.0f; 259 for (int i=0; i<64; i++) { 260 bimages[i] = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB); 261 Graphics g = (Graphics)bimages[i].createGraphics(); 262 g.fillRect(0, 0, 64, 64); 263 float h = dh * (float)i; 264 Color c = Color.getHSBColor(h, 1.0f, 1.0f);//年輪の色 265 g.setColor(c); 266 for (int j=0; j<8; j++) { 267 int x = j * 4; 268 int w = 64 - x * 2; 269 System.out.println("i=" + i + ", j=" + j + ", x=" + x + ", w=" + w + ", h" + h);//DEBUG 270 g.drawOval(x, x, w, w); 271 } 272 } 273 274 ImageComponent3D icompo3d = 275 new ImageComponent3D(ImageComponent.FORMAT_RGBA, bimages); 276 277 Texture3D texture3d = 278 new Texture3D(Texture.BASE_LEVEL, Texture.RGBA, 64, 64, 64); 279 texture3d.setImage(0, icompo3d); 280 281 app.setTexture(texture3d); 282 283 txattr_ = new TextureAttributes(); 284 txattr_.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE); 285 txattr_.setTextureMode(TextureAttributes.FASTEST); 286 Transform3D t3d = new Transform3D(); 287 t3d.rotX(Math.PI / 2.0); 288 txattr_.setTextureTransform(t3d); 289 app.setTextureAttributes(txattr_); 290 291 texgen_ = 292 new TexCoordGeneration( TexCoordGeneration.EYE_LINEAR, 293 TexCoordGeneration.TEXTURE_COORDINATE_3 ); 294 texgen_.setCapability(TexCoordGeneration.ALLOW_MODE_READ); 295 texgen_.setPlaneS(new Vector4f(1.0f, 0.0f, 0.0f, 0.0f)); 296 texgen_.setPlaneT(new Vector4f(0.0f, 1.0f, 0.0f, 0.0f)); 297 texgen_.setPlaneR(new Vector4f(0.0f, 0.0f, 1.0f, 0.0f)); 298 app.setTexCoordGeneration(texgen_); 299 300 pattr_ = new PolygonAttributes(); 301 pattr_.setCapability(PolygonAttributes.ALLOW_MODE_WRITE); 302 pattr_.setCapability(PolygonAttributes.ALLOW_CULL_FACE_WRITE); 303 app.setPolygonAttributes(pattr_); 304 305 return app; 306 } 307 308 public static void main(String[] args) { 309 Texture3DTest applet = new Texture3DTest(true); // isStandalone = true; 310 Frame frame = new MainFrame(applet, 500, 500); 311 } 312 }
256行目で BufferedImage
の配列を生成しています。今回は 64×64
ピクセルの BufferedImage
を 64層使用することにします。テクスチャーの縦、横のサイズは 必ず2n のピクセル数である必要があります。
258〜272行目で3次元テクスチャーの元になるグラフィックを BufferedImage
に描画しています。色の生成は HSB で行っています。258行目で、ループごとの色相値の増加分を計算しています。260行目で 64×64
ピクセルの BufferedImage
のインスタンスを生成し、264行目で Color#getHSBColor()
メソッドを使って Color
オブジェクトを生成しています。
各層ごとに 8つの同心円を描くため、266〜271行目の for
ループを使用しています。270行目で Graphics#drawOval()
メソッドを使って円を描画しています。
274〜275行目で javax.media.j3d.ImageComponent3D
を生成しています。コンストラクターの引数として、64×64ピクセル×64層の BufferedImage
を指定しています。
277〜278行目で javax.media.j3d.Texture3D
を生成しています。width, height, depth
はすべて 64
です。
279行目では setImage()
メソッドを使って Texture3D
に ImageComponent3D
を設定しています。
289行目では setTexture()
メソッドを使って javax.media.j3d.Appearance
に Texture3D
を設定しています。
テクスチャーに回転を与えるため、TextureAttributes#setTextureTransform()
メソッドを使用しています。
283行目で TextureAttributes
オブジェクトを生成しています。286行目で javax.media.j3d.Transform3D
を生成し、287行目で rotX()
メソッドを使って X軸を回転中心に π/2
ラジアン (90°) 回転させています。回転を与えた Transform3D
は、288行目で setTextureTransform()
メソッドを使って TextureAttributes
に設定されています。
291〜293行目で javax.media.j3d.TexCoordGeneration
を生成しています。テクスチャー座標は s, t, r
の3次元座標です。
295〜297行目で S, T, R
各座標の平面方程式を設定しています。
298行目で setTexCoordGeneration()
メソッドを使って TexCoordGeneration
を Appearance
に設定しています。
300行目では javax.media.j3d.PolygonAttributes
を生成し、303行目で setPolygonAttributes()
メソッドを使って Appearance
に設定しています。
今回は Box, Cone, Cylinder, Sphere
など com.sun.j3d.utils.geometry.Primitive
のサブクラスを使いました。例えば javax.media.j3d.PointArray
を使用して点の集合を描画すると、星雲状の色の付いた点などを描画できるかも知れません。
最後に繰り返しますが、現時点では3次元テクスチャーは Win32 では動作しません。
Java 3D をはじめとする、Java を使った3次元グラフィックスについての話題を中心にした日本語のメーリングリストがあります。管理者は えんどう です。
1999年1月のスタートから、現在までに約 900通の投稿がありました。
メーリングリストの名称は Java3Djp
です。
メーリングリストへの参加方法は下記のページを参照してください。
Java3Djpメーリングリスト http://www.ipc-tokai.or.jp/~atusi/java3d/ml/index.html
なお、1999年1月から8月上旬までの ML アーカイブが下記からダウンロードできます。
http://www.javaopen.org/jfriends/java3djp.txt.bz2
bzip2 で圧縮されています。UNIX mbox 形式で、漢字コードは JIS です。
また、ML アーカイブは下記 URL から HTML 形式で参照できます。
http://www.javaopen.org/j3dbook/mlarchive/threads.html
Java や3次元グラフィックに興味がある方は、気軽に参加してみてください。えんどう の原稿についてのご質問もぜひどうぞ。
次期バージョンである Java 3D 1.2 の Alpha1 が 9月にリリースされました。
今回の主な強化点は、オフスクリーン・レンダリングの導入です。
javax.media.Canvas3D
は、バージョン 1.1 ではスクリーン(グラフィクス画面) にしか描画できません。また、描画されたグラフィックを取り出して再利用するのがとても面倒です。
オフスクリーン・レンダリングは、スクリーンではなくメモリー中のバッファーに描画しするモードで、レンダリング画像の再利用や印刷のためのデータなどにして使用できます。
例えば、視点からではなく光源から見た画像をオフスクリーン・レンダリングして"影"テクスチャーとして利用したりできるそうです。
また、Java 3D 1.1 は JFC Swing のような軽量コンポーネントと重ねた場合に、軽量コンポーネントを覆ってしまうという現象があります。(Java 3D 以外でも、AWT と Swing の混在などの際に発生します)
オフスクリーン・レンダリングを使って、いったんオフスクリーン・バッファーに描画した画像を Swing コンポーネントに転送するような描画方法でこの問題を回避することができます。ただしパフォーマンスは低下すると思います。
Java 3D 1.1.x には印刷のための API がありませんが、オフスクリーン・レンダリングが導入されれる 1.2 では印刷用 API が提供されます。
このほか、Shape3D
が複数の Geometry
を持てるようになる、全体的なパフォーマンスの向上など、様々な改良点があるようです。
えんどう の予想では、Solaris/Win32 用の JDK 1.3 が正式リリースになる年末頃には Java 3D 1.2 正式版がリリースされるのではないかと思っています。早ければ、この号が店頭に並ぶ頃にはリリースされているかも知れません。
Java 3D 1.2 については下記を参照してください。
http://java.sun.com/products/java-media/3D/1_2_api/
Linux での Java 3D 開発は、環境構築さえ終ってしまえば非常に安定しています。Win32 では使えない3次元テクスチャーなども手軽に試せます。ぜひ Linux で Java 3D プログラミングを楽しんでください。
Java 3D で3次元グラフィックに入門したら、次は Mesa で OpenGL プログラミングも楽しいと思います。
えんどう は、今後 Linux で Java, C/C++ によるマルチメディア・プログラミングをやってみたいと思っています。サウンド入出力や、様々な入出力ディバイスを使ったインタラクティブなものが面白そうです。