Linux で Java 3D を使おう!

各ソフトウエアの一次配布先について 2000.1.10

雑誌発表後、 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 が公開されています。

註:
現在、正式には JavaTM 2 SDK Standard Edition Version 1.2 というような表記になっているようですが、ここでは従来通り JDK (Java Development Kit) 1.2 という表記を使用します。

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/

blackdown.gif

また、既知のバグについての情報は必ず参照してください。

http://www.blackdown.org/java-linux/jdk1.2-status/known-bugs.html

linuxbugs.gif

以下では、次のソフトウエアのインストールを説明して行きます。

えんどう は Vine Linux 1.0beta でインストールしました。Vine Linux 1.1 でもほぼ同様にインストールできると思います。

インストールが終ったら、次のトピックスをとりあげます。

Java 2 SDK (JDK 1.2) for Linux, version pre-release 2の入手

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に関しては、下記のサイトをご参照ください。

http://vine.flatout.org/

JDK 1.2のインストール

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 -

bzip2のインストールについて

えんどう が使用する Vine Linux 1.0 beta には bzip2 が含まれていますが、標準インストール時には bzip2 がインストールされないようです。Vine Linux 1.1 では、Vine のインストールで bzip2 もインストールされると思います。

bzip2については下記サイトをご参照ください。

http://sourceware.cygnus.com/bzip2/index.html

環境変数PATHの設定

JDK 1.2を動作させるには、環境変数PATHにJDKのbinディレクトリーが含まれている必要があります。
bashでは次のように設定します。JDK 1.2 のインストール・ディレクトリーが例と異なる場合は適宜変更してください。

$ export PATH=/usr/local/jdk1.2/bin:$PATH

JDKの動作テスト

コマンドラインから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]

swingset.gif

メニューのフォントが文字化けしていますが、いちおう実行できています。

フォントエラーの解消と日本語フォントの使用

前項の例で発生していた 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 ファイルがそのまま使用できます。

kinput2 での日本語入力

JFC Swing 上で kinput2 を使用する場合、kinput2 のバージョンによっては日本語入力ができない場合があります。

えんどう は次の RPM をダウンロードしてインストールしました。

ftp://ftp.lab.kdd.co.jp/Linux/packages/Vine/Vine-1.0/i386/Vine/RPMS/kinput2-v2-fix5-alpha7-1.i386.rpm

えんどう がダウンロードしたのは、以下のファイル名とファイル容量のものです。

kinput2-v2-fix5-alpha7-1.i386.rpm 151,497バイト

JIT の問題点

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つの方法があります。

別の対処方法として、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つの方法があります。

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_profilesJAVA_COMPLIER=shujit を指定しています。

JBuider Java 2 Just-In-Time Complire for Linux

9月27日に、Borland (INPRISE) から Linux 用の JIT コンパイラー JBuilder Java 2 Just-In-Time Compiler for Linux がリリースされました。JBuilder のために開発されたもので、かなり高速なようです。

http://www.borland.com/jbuilder/linux

からダウンロードできます。ただし残念なことに、オープンソースではないようです。

native thread の問題点

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つの方法があります。

native thread に関する問題点は、Linux 用の JDK 1.2 の正式リリースまでには解消されるのではないか、というのが えんどう の予想です。

Mesaのインストール

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.rpm443,581バイト// Mesa 3.0.2
Mesa-glut-3.0-2.i386.rpm102,429バイト// Mesa glut 3.0.2
Mesa-devel-3.0-2.i386.rpm559,672バイト// Mesa開発用ヘッダーファイル
Mesa-glut-devel-3.0-2.i386.rpm121,121バイト// Mesa glut開発用ヘッダーファイル
Mesa-demos-3.0-2.i386.rpm1,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の動作テストをしてみましょう。
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 

mesademo.gif

Java 3D も面白いですが、C で OpenGL (Mesa) プログラミングも面白いと思います。OpenGL プログラミングについては次の書籍を参考にしてください。

書名: OpenGL プログラミングガイド (第2版)
      OpenGL バ−ジョン 1.1 対応オフィシャルガイド
ISBN: 479529710X
著者: OpenGL ARB (Aachitecture Review Board) 
出版社: アジソン・ウェスレイ・パブリッシャ−ズ・(星雲社刊)
本体価格: ¥12,000-

Mesa 環境でのグラフィックス・ハードウエア・アクセラレーションについて

グラフィックス・ボードのハードウエア・アクセラレーションがあると、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 での 3D グラフィックス環境 (GLX, Mesa)

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 グラフィック環境はますます充実するのではないかと思います。

Java 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の実行テスト

Java 3Dのデモを実行してみます。

$ cd /usr/local/jdk1.2/demo/java3d/HelloUniverse/
$ java HelloUniverse

hellou-linux.gif

Win32 では、ガベージコレクションのときアニメーションが一瞬止まって見えるという現象がありましたが、Linux ではこの現象はほとんど気になりません。
Linux用のJava 3Dの完成度はかなり高いと思います。

Linux での Java 3D プログラミング - 3次元テクスチャー -

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 が付属しています。

stex3d.gif

3次元テクスチャーとはどういうものでしょうか。

2次元テクスチャーは「1枚の絵」と考えてください。テクスチャーをポリゴンに張り付けるのにはテクスチャー座標というものを使用します。テクスチャーは 0.0〜1.0 の範囲の2次元テクスチャー座標 s, t の間に引き延ばされ (または縮められ) る、と思ってください。s は右方向、t は上方向が正方向(プラス方向)になります。

TXCOORD_2.jpg

ポリゴンの各頂点にテクスチャー座標 (s, t) を設定し、ポリゴンにテクスチャーをマッピングします。

TextureApplet1.gif

3次元テクスチャーは「複数枚の重なった絵」と考えてください。3次元のテクスチャー座標は s, t に加えて r 座標を持ちます。r は奥行き(深さ)方向が正方向になります。

CircleImage.gif

TEXCOORD_3.gif

たとえば、木の年輪を考えてください。年輪は木の中で同心円の円柱のように重なっています。この木を任意の形に掘り出すと、木彫りの彫刻の表面には年輪の模様が描かれます。

年輪のような同心円状の絵が複数重なった3次元テクスチャーを作成したとします。任意の形状の物体にこのテクスチャーを適用すると、物体の表面には木彫りの彫刻の表面のような年輪状の模様が描かれることになります。

3次元テクスチャーは、ポリゴンの頂点に (s, t, r) で表現されるテクスチャー座標を適用し、テクスチャーをポリゴンにマッピングします。

サンプル・プログラムの実行例を見てください。

Texture3DTest.gif

このサンプルでは、com.sun.j3d.utils.behaviors.pickig パッケージを使って、マウスの左/ 中/右ボタンで回転/ズーム/移動ができるようになっています。

年輪のような3次元テクスチャーを作成し、年輪の色を深さに応じて変化させています。また、通常のテクスチャーは年輪を真上から見たような方向になるため、javax.media.j3d.TextureAttributes を使って X軸を回転軸にテクスチャーを 90°回転させています。ウインドウの下部の TextFieldx, 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.java
  1 // 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() メソッドを使って Texture3DImageComponent3D を設定しています。

289行目では setTexture() メソッドを使って javax.media.j3d.AppearanceTexture3D を設定しています。

テクスチャーに回転を与えるため、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() メソッドを使って TexCoordGenerationAppearance に設定しています。

300行目では javax.media.j3d.PolygonAttributes を生成し、303行目で setPolygonAttributes() メソッドを使って Appearance に設定しています。

今回は Box, Cone, Cylinder, Sphere など com.sun.j3d.utils.geometry.Primitive のサブクラスを使いました。例えば javax.media.j3d.PointArray を使用して点の集合を描画すると、星雲状の色の付いた点などを描画できるかも知れません。

最後に繰り返しますが、現時点では3次元テクスチャーは Win32 では動作しません

Java3Djp メーリングリストについて

Java 3D をはじめとする、Java を使った3次元グラフィックスについての話題を中心にした日本語のメーリングリストがあります。管理者は えんどう です。

1999年1月のスタートから、現在までに約 900通の投稿がありました。

メーリングリストの名称は Java3Djp です。

Java3Djp.gif

メーリングリストへの参加方法は下記のページを参照してください。

Java3Djpメーリングリスト http://www.ipc-tokai.or.jp/~atusi/java3d/ml/index.html

Java3DTips_Java3Djp.gif

なお、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 の今後の展望について

次期バージョンである 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/

Java3D12.gif

最後に

Linux での Java 3D 開発は、環境構築さえ終ってしまえば非常に安定しています。Win32 では使えない3次元テクスチャーなども手軽に試せます。ぜひ Linux で Java 3D プログラミングを楽しんでください。

Java 3D で3次元グラフィックに入門したら、次は Mesa で OpenGL プログラミングも楽しいと思います。

えんどう は、今後 Linux で Java, C/C++ によるマルチメディア・プログラミングをやってみたいと思っています。サウンド入出力や、様々な入出力ディバイスを使ったインタラクティブなものが面白そうです。