テクスチャーマッピングは、ポリゴンの表面に2次元や3次元の画像を適用します。(1次元の場合もありますが、Java 3Dには1次元テクスチャーのクラスはありません)
テクスチャーマッピングのための画像は、GIF, JPEG
などのグラフィックファイルを読み込んで生成することができます。また、java.awt.image.BufferedImage
を使ってプログラム中で生成することもできます。
2次元テクスチャーは「1枚の絵」と考えてください。
テクスチャーをポリゴンに張り付けるのにはテクスチャー座標というものを使用します。
テクスチャーは 0.0〜1.0
の範囲の2次元テクスチャー座標
s, t
の間に引き延ばされ (または縮められ) る、
と考えてください。
s
は右方向、
t
は上方向が正方向(プラス方向)になります。
ポリゴンの各頂点にテクスチャー座標 (s, t)
を設定し、ポリゴンにテクスチャーをマッピングします。
この例では四角形ポリゴン (QuadArray
) の 4つの頂点にテクスチャー座標を設定し、テクスチャーマッピングしています。
テクスチャー座標はテクスチャーが持つ独自の座標系で、Java 3Dの仮想空間における3次元座標とは別個の座標系です。
ポリゴンの各頂点にテクスチャー座標を設定すると、ポリゴンの各ピクセルがテクスチャーの各テクセルの色で描画されます。テクスチャーのピクセルのことを"テクセル"と言うことがあります。
ポリゴンの各ピクセルに対してテクスチャーのどのテクセルが対応するかは、ポリゴンの頂点に設定したテクスチャー座標によって決定されます。頂点間の各ピクセルは、「頂点に設定したテクスチャー座標」間のテクセルによってそれぞれ描画されます。
0.0〜1.0
の範囲を超えるテクスチャー座標を適用した場合はどうなるでしょうか。
0.0〜1.0
の範囲を超えたときに、テクスチャーを繰り返し適用することができます。テクスチャーを繰り返し適用するモードを WRAP
と呼びます。
0.0〜1.0
の範囲だけにテクスチャーを適用することもできます。テクスチャーを0.0〜1.0
の範囲だけに適用するモードを CLAMP
と呼びます。
3次元テクスチャーは「複数枚の重なった絵」と考えてください。3次元のテクスチャー座標は s, t
に加えて r
座標を持ちます。r
は奥行き(深さ)方向が正方向になります。
たとえば、木の年輪を考えてください。年輪は木の中で同心円の円柱のように重なっています。この木を任意の形に掘り出すと、木彫りの彫刻の表面には年輪の模様が描かれます。
年輪のような同心円状の絵が複数重なった3次元テクスチャーを作成したとします。任意の形状の物体にこのテクスチャーを適用すると、物体の表面には木彫りの彫刻の表面のような年輪状の模様が描かれることになります。
3次元テクスチャーは、ポリゴンの頂点に (s, t, r)
で表現されるテクスチャー座標を適用し、テクスチャーをポリゴンにマッピングします。
サンプルの実行例を見てください。
年輪のような3次元テクスチャーを作成し、年輪の色を深さに応じて変化させています。物体の表面に年輪状のテクスチャーが適用されます。
javax.media.j3d.Texture
javax.media.j3d.Texture
はテクスチャーマッピングの形式、画像フォーマット、画像の幅、高さなどを定義し、テクスチャーマップのための javax.media.j3d.ImageComponent
オブジェクトを保持します。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.Texture クラス宣言 public abstract class Texture extends NodeComponent
Texture
は抽象クラスです。実際にはそのサブクラスである javax.media.j3d.Texture2D, javax.media.j3d.Texture3D
を使用します。
コンストラクター public Texture() public Texture(int mipMapMode, // MipMap形式 int format, // テクスチャーフォーマット int width, // 幅 int height) // 高さ 定数フィールド (一部) public static final int BASE_LEVEL // 基本レベルの画像のみ public static final int MULTI_LEVEL_MIPMAP // 複数の MipMap レベルを指定する
Texture
のコンストラクターでは、MipMap形式、テクスチャーフォーマット、テクスチャーの幅、高さなどを指定します。
MipMapとは何でしょうか。
128×128 | 64×64 | 32×32 | 16×16 | 8×8 | 4×4 | 2×2 | 1×1 |
通常遠くにある物体は小さく描画されますので、遠くの物体に解像度が高いテクスチャー画像を適用しても無意味です。
逆に、視点の近くにある物体に解像度が低いテクスチャーが適用してあると、テクスチャー画像のピクセル(余談ですがこれを「テクセル」と呼ぶことがあります)が拡大されてリアル感を損なうことになります。
視点からの距離に応じて適切なテクスチャー画像を適用するには、あらかじめ複数のテクスチャー画像を指定して、距離に応じて切替えるという技法があります。このために、徐々に解像度が小さくなっていく複数の画像が必要です。この複数の画像を MipMap と呼びます。
mipMapMode
が BASE_LEVEL
のときは距離に関係なく一つのテクスチャー画像(基本レベルテクスチャー)が適用されます。デフォルトは BASE_LEVEL
です。
mipMapMode
が MULTI_LEVEL_MIPMAP
のときは距離に応じた複数のテクスチャー画像を適用します。MULTI_LEVER_MIPMAP
を指定した場合、すべての MipMap レベルのテクスチャー画像を用意して適用しておく必要が生じます。
format
にはテクスチャー画像のフォーマットを指定します。これには次のものがあります。
定数フィールド (一部) public static final int INTENSITY // 輝度のみ public static final int LUMINANCE // 光度のみ public static final int ALPHA // 不透明度(アルファ値)のみ public static final int LUMINANCE_ALPHA // 光度と不透明度(アルファ値) public static final int RGB // 赤、緑、青の色 public static final int RGBA // 赤、緑、青、不透明度(アルファ値)
テクスチャー画像のフォーマットは RGB, RGBA
が多いと思いますが、INTENSITY
(輝度のみ)、LUMINANCE
(光度のみ)、ALPHA
(不透明度のみ)、LUMINANCE_ALPHA
光度と不透明度(アルファ値)を選ぶこともできます。
javax.media.j3d.TextureAttributes
を設定いて、物体の色とテクスチャー画像をいろいろなモードで混合することができます。輝度のみ、光度のみ、不透明度のみ、光度と不透明度などのフォーマットのテクスチャーと物体の色を混合すると様々な効果が得られると思います。
もちろん RGB, RGBA
形式のテクスチャー画像と混合することも可能です。
テクスチャー画像の設定には Texture#setImage(), Texture#setImages()
メソッドを使用します。
メソッド (一部) public final void setImage(int level, // MipMapレベル ImageComponent image) // テクスチャー画像の ImageComponent public final void setImages(ImageComponent[] images) // 複数の MipMapレベルに応じた ImageComponent の配列
テクスチャー画像は、javax.media.j3d.ImageComponent
オブジェクトで指定します。ImageComponent
は抽象クラスで、実際にはそのサブクラスの ImageComponent2D, ImageComponent3D
を使用します。
mipMapMode
に BASE_LEVEL
を指定したとき、基本レベルの ImageComponent
を一つだけ設定します。このとき、setImage()
の引数の level
(MipMapレベル)は 0
です。
mipMapMode
に MULTI_LEVEL_MIPMAP
を指定したとき、すべてのMipMapレベルの ImageComponent
が必要です。
MipMapレベルの数はテクスチャー画像の大きさによって一意に決まります。
テクスチャー画像のサイズは 2n×2n
ピクセルの正方形である必要があります。
128×128 | 64×64 | 32×32 | 16×16 | 8×8 | 4×4 | 2×2 | 1×1 |
このとき (n+1)
の数の MipMapレベルが必要になります。(基本レベルを含む)
例えばテクスチャー画像のサイズが 128×128
ピクセル (27×27
ピクセル) のとき、(7+1)
の数の MipMapレベルが必要です。
128×128
ピクセルの基本レベルから 64×64, 32×32, 16×16, 8×8, 4×4, 2×2 ...
と徐々に解像度を低下させて行き、最終的には 1×1
ピクセルまで解像度を低下させます。
mipMapMode
に MULTI_LEVEL_MIPMAP
を指定したとき、すべての MipMapレベルに応じた、異なる解像度の複数のテクスチャー画像を作成する必要があります。
ポリゴンの頂点に指定したテクスチャー座標が 0.0〜1.0
の範囲を超えるとき、テクスチャーを繰り返し適用するか、それとも 0.0〜1.0
の範囲だけにテクスチャーを適用するかを選ぶことができます。
このためのメソッドが setBoundaryModeS(), setBoundaryModeT()
です。
メソッド (一部) public final void setBoundaryModeS(int boundaryModeS) // S座標方向の境界形式 public final void setBoundaryModeT(int boundaryModeT) // T座標方向の境界形式 定数フィールド (一部) public static final int CLAMP // テクスチャーを[0, 1]の範囲にクランプする public static final int WRAP // テクスチャーを繰り返す
S座標方向、T座標方向それぞれに対して、テクスチャーの適用を CLAMP
または WRAP
に指定することができます。デフォルトは WRAP
です。
テクスチャー画像のピクセル(テクセル)が描画時のピクセルと一致しないとき、最も近いテクセルをそのまま適用するか、周囲の複数のテクセルから補間するかを選ぶことができます。このためのメソッドが setMagFilter(), setMinFilter()
です。
メソッド (一部) public final void setMagFilter(int magFilter) // 拡大フィルターを設定 public final void setMinFilter(int minFilter) // 縮小フィルターを設定 定数フィールド (一部) public static final int FASTEST // 可能な限り高速なフィルターを使用 public static final int NICEST // 可能な限り高品質なフィルターを使用 public static final int BASE_LEVEL_POINT // 基本レベルのテクスチャーの最も近いテクセルを適用 public static final int BASE_LEVEL_LINEAR // 基本レベルのテクスチャーの最も近い4テクセルを補間して適用 public static final int MULTI_LEVER_POINT // 最も近い MipMap での最も近いテクセルを適用 public static final int MULTI_LEVEL_LINEAR // 最も近い2つの MipMap でのそれぞれの4テクセルを補間して適用
setMagFilter()
は拡大フィルターを、setMinFilter()
は縮小フィルターを設定します。
デフォルト値は BASE_LEVEL_POINT
です。ピクセルに最も近い、基本レベルテクスチャーのテクセルが適用されます。
複数の MipMapレベルを指定してある場合、MULTI_LEVEL_POINT
を指定すると最も近いレベルのひとつの MipMap が選択され、その最も近いテクセルが適用されます。
BASE_LEVEL_LINEAR
を指定すると、ピクセルに最も近い4つのテクセルを加重平均したものが適用されます。
複数の MipMapレベルを指定してある場合、MULTI_LEVEL_LINEAR
を指定すると最も近いレベルの2つの MipMap が選択され、最も近いそれぞれ4つのテクセルを加重平均したものが適用されます。
javax.media.j3d.ImageComponent
javax.media.j3d.ImageComponent
はテクスチャーマッピングのための画像を保持するためのクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.ImageComponent クラス宣言 public abstract class ImageComponent extends NodeComponent コンストラクター (一部) public ImageComponent(int format, // 画像フォーマット int width, // 幅 int height) // 高さ
ImageComponent
は抽象クラスであり、実際にはサブクラスの ImageComponent2D, ImageComponent3D
を使用します。
format
には画像フォーマットを指定します。画像フォーマットには次のものがあります。
定数フィールド (一部) public static final int FORMAT_RGB // 各8ビットの赤、緑、青 public static final int FORMAT_RGBA // 各8ビットの赤、緑、青、不透明度 public static final int FORMAT_RGB8 // 各8ビットの赤、緑、青 public static final int FORMAT_RGBA8 // 各8ビットの赤、緑、青、不透明度 public static final int FORMAT_RGB5 // 各5ビットの赤、緑、青 public static final int FORMAT_RGB5_A1 // 各5ビットの赤、緑、青と、1ビットの不透明度 public static final int FORMAT_RGB4 // 各4ビットの赤、緑、青 public static final int FORMAT_RGBA4 // 各4ビットの赤、緑、青、不透明度 public static final int FORMAT_LUM4_ALPHA4 // 4ビットの光度と4ビットの不透明度 public static final int FORMAT_LUM8_ALPHA8 // 8ビットの光度と8ビットの不透明度 public static final int FORMAT_R3_G3_B2 // 各3ビットの赤、緑と2ビットの青 public static final int FORMAT_CHANNEL8 // 8ビットの 光度または不透明度または輝度(どれか一種類)
これらの画像フォーマットは、Texture
での画像フォーマット指定に対応いています。
javax.media.j3d.Texture の定数フィールド (一部) public static final int INTENSITY // 輝度のみ public static final int LUMINANCE // 光度のみ public static final int ALPHA // 不透明度(アルファ値)のみ public static final int LUMINANCE_ALPHA // 光度と不透明度(アルファ値) public static final int RGB // 赤、緑、青の色 public static final int RGBA // 赤、緑、青、不透明度(アルファ値)
javax.media.j3d.Texture2D
javax.media.j3d.Texture2D
は2次元テクスチャーのためのクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.Texture | +--javax.media.j3d.Texture2D クラス宣言 public class Texture2D extends Texture コンストラクター public Texture2D() public Texture2D(int mipmapMode, // MipMap形式 int format, // 画像フォーマット int width, // 幅 int height) // 高さ
Texture
から特に拡張された点はありません。2次元テクスチャーを使用する場合は Texture2D
を使うことになります。
javax.media.j3d.ImageComponent2D
javax.media.j3d.ImageComponent2D
は2次元テクスチャーのための画像を保持します。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.ImageComponent | +--javax.media.j3d.ImageComponent2D クラス宣言 public class ImageComponent2D extends ImageComponent コンストラクター (一部) public ImageComponent2D(int format, // 画像フォーマット int width, // 幅 int height) // 高さ public ImageComponent2D(int format, // 画像フォーマット java.awt.image.BufferedImage image) // テクスチャー画像の BufferedImage
ImageComponent2D
では ImageComponent
で宣言されているコンストラクターに加えて、java.awt.image.BufferedImage
を引数として指定するコンストラクターが増えています。
ImageComponent2D
には BufferedImage
を設定するためのメソッドもあります。
メソッド (一部) public final void set(java.awt.image.BufferedImage image) // テクスチャー画像の BufferedImage
ファイルから読み込んで BufferedImage
に画像を保存したり、プログラム中で BufferedImage
に描画するなどの方法でテクスチャーを作成します。
サンプルのソースはつぎの通りです。
TextureApplet.java1 // Java 3D Test Applet 2 // TextureApplet.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.behaviors.mouse.MouseRotate; 17 import com.sun.j3d.utils.behaviors.mouse.MouseTranslate; 18 import com.sun.j3d.utils.behaviors.mouse.MouseZoom; 19 20 public class TextureApplet extends Applet { 21 private boolean isStandalone = false;....................(1) 22 23 public TextureApplet() {.................................(2) 24 this(false); 25 } 26 27 public TextureApplet(boolean isStandalone) {.............(3) 28 this.isStandalone = isStandalone; 29 30 this.setLayout(new BorderLayout()); 31 32 } 33 34 public void init() {.....................................(4) 35 GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); 36 Canvas3D canvas = new Canvas3D(config); 37 this.add(canvas, BorderLayout.CENTER); 38 39 SimpleUniverse universe = new SimpleUniverse(canvas); 40 universe.getViewingPlatform().setNominalViewingTransform(); 41 42 BranchGroup scene = createSceneGraph(); 43 44 universe.addBranchGraph(scene); 45 } 46 47 private BranchGroup createSceneGraph() { 48 BranchGroup root = new BranchGroup(); 49 50 Background bg = new Background(new Color3f(0.5f, 0.5f, 0.5f)); 51 bg.setApplicationBounds(new BoundingSphere(new Point3d(), 100.0)); 52 root.addChild(bg); 53 54 TransformGroup trans = new TransformGroup(); 55 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 56 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 57 58 BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0); 59 60 MouseRotate rotator = new MouseRotate(trans); 61 rotator.setSchedulingBounds(bounds); 62 root.addChild(rotator); 63 64 MouseTranslate translator = new MouseTranslate(trans); 65 translator.setSchedulingBounds(bounds); 66 root.addChild(translator); 67 68 MouseZoom zoomer = new MouseZoom(trans); 69 zoomer.setSchedulingBounds(bounds); 70 root.addChild(zoomer); 71 72 Point3d[] vertices = new Point3d[4]; 73 vertices[0] = new Point3d(-0.4, -0.4, 0.0); // 左下 3+-----+2 74 vertices[1] = new Point3d( 0.4, -0.4, 0.0); // 右下 | | 75 vertices[2] = new Point3d( 0.4, 0.4, 0.0); // 右上 | | 76 vertices[3] = new Point3d(-0.4, 0.4, 0.0); // 左上 0+-----+1 77 78 Point2f[] txcoords = new Point2f[4]; ┐ 79 txcoords[0] = new Point2f(0.0f, 0.0f); // 左下 3+-----+2 │ 80 txcoords[1] = new Point2f(1.0f, 0.0f); // 右下 | | ├(5) 81 txcoords[2] = new Point2f(1.0f, 1.0f); // 右上 | | │ 82 txcoords[3] = new Point2f(0.0f, 1.0f); // 左上 0+-----+1 ┘ 83 84 QuadArray geom = 85 new QuadArray( vertices.length, 86 GeometryArray.COORDINATES | 87 GeometryArray.TEXTURE_COORDINATE_2 );...(6) 88 geom.setCapability(Geometry.ALLOW_INTERSECT); 89 geom.setCoordinates(0, vertices); 90 geom.setTextureCoordinates(0, txcoords);.................(7) 91 92 Appearance ap = createAppearance(); 93 94 Shape3D grid = new Shape3D(geom, ap); 95 grid.setCapability(Shape3D.ALLOW_GEOMETRY_READ); 96 trans.addChild(grid); 97 98 root.addChild(trans); 99 100 return root; 101 } 102 103 private Appearance createAppearance() { 104 Appearance app = new Appearance(); 105 106 Image image = null;......................................(9) 107 if (this.isStandalone) { 108 // アプリケーションとして実行されている 109 final Toolkit toolkit = Toolkit.getDefaultToolkit(); ┬(10) 110 image = toolkit.getImage("face.gif"); ┘ 111 } else { 112 // アプレットとして実行されている 113 image = getImage(getCodeBase(), "face.gif");.........(11) 114 } 115 MediaTracker mt = new MediaTracker(this); ┐ 116 mt.addImage(image, 0); │ 117 mt.checkAll(true); ├(12) 118 try { mt.waitForID(0); } │ catch (InterruptedException e) { e.printStackTrace(); } ┘ 119 120 BufferedImage bimage = new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB);....(13) 121 int[] imagefield = ((DataBufferInt)bimage.getRaster().getDataBuffer()).getData();...(14) 122 PixelGrabber pg = new PixelGrabber(image, 0, 0, 128, 128, imagefield, 0, 128);......(15) 123 try { pg.grabPixels(); } catch (InterruptedException e) { e.printStackTrace(); }....(16) 124 125 ImageComponent2D icompo2d = 126 new ImageComponent2D(ImageComponent.FORMAT_RGBA, bimage);.........................(17) 127 128 Texture2D texture2d = 129 new Texture2D(Texture.BASE_LEVEL, Texture.RGBA, 128, 128);........................(18) 130 texture2d.setImage(0, icompo2d);....................................................(19) 131 132 app.setTexture(texture2d);..........................................................(20) 133 134 return app; 135 } 136 137 public static void main(String[] args) { 138 TextureApplet applet = new TextureApplet(true); // isStandalone = true;.............(21) 139 Frame frame = new MainFrame(applet, 500, 500); 140 } 141 }
アプリケーションとしてもアプレットとしても動作するようにしました。(1)でuアプリケーションとして実行されているとき true
、アプレットとして実行されているとき false
の状態をとるフラグ isStandalone
を宣言しています。
アプレットとして実行されるときに使われる引数無しのコンストラクター (2) の中では、boolean
の引数をとるコンストラクター (3) を引数 false
で実行しています。
boolean
の引数をとるコンストラクター (3u) では、引数の値を isStandalone
に代入し、レイアウトマネジャーに java.awt.BorderLayout
を指定しているだけです。
画像を URL を使って読み込むために、
シーングラフの構築をコンストラクターから
init()
メソッドに移動しました(4)。
アプレットのコンストラクターでは URL からのファイル読み込みが出来ないためです。
この例ではひとつの四角形ポリゴン (QuadArray
)に
ひとつのテクスチャーを適用しています。
(5)でテクスチャー座標配列を生成/初期化しています。
テクスチャー座標はテクスチャーの左下を原点とし、
テクスチャーの右上を (1.0, 1.0)
とする、
横軸が s
、縦軸が t
の座標系です。
QuadArray
にテクスチャー座標を設定したいので、
QuadArray
のコンストラクターで
GeometryArray.TEXTURE_COORDINATE_2
を指定しています(6)。
(7)で setTextureCoordinates()
メソッドを使ってテクスチャー座標を設定しています。テクスチャー座標の数は、頂点座標の数と同じである必要があります。
この例は GeometryArray
のサブクラスを使っています。GeometryArray
のサブクラスでのテクスチャー座標の指定方法は次のようになります。
double, float
の配列の場合、配列要素数/2が頂点数になる。3次元テクスチャーでは 配列要素数/3が頂点数)TEXTURE_COORDINATE_2
(2次元テクスチャー)または TEXTURE_COORDINAME_3
(3次元テクスチャー) を指定する。setCoordinates()
で頂点配列を設定する。setTextureCoordinates()
でテクスチャー座標配列を設定する。GometryArray
をコンストラクター引数にして Shape3D
を生成する。Shape3D
をシーングラフに addChild()
する。IndexedGeometryArray
の場合はつぎのような手順になります。
TEXTURE_COORDINATE_2
(2次元テクスチャー)または TEXTURE_COORDINAME_3
(3次元テクスチャー) を指定する。setCoordinates()
で頂点配列を設定する。setCoordinateIndices()
で頂点配列の index を設定する。setTextureCoordinates()
でテクスチャー座標配列を設定する。setTextureCoordinateIndices()
でテクスチャー座標配列の index を設定する。これは頂点 index と同じものを使用する。IndexedGometryArray
をコンストラクター引数にして Shape3D
を生成する。Shape3D
をシーングラフに addChild()
する。画像の読み込みですが、アプリケーションとしてもアプレットとしても動作するように若干複雑なコーディングをしています。
(8)で画像のための java.awt.Image
を宣言しています。
(9)の if
文で isStandalone
フラグをみてアプリケーションとして実行されているのか、アプレットとして実行されているのかを判定しています。
アプリケーションとして実行されているときは、java.awt.Toolkit
クラスの static
メソッドである getDefaultToolkit()
で現在の Toolkit
オブジェクトを取得して、Toolkit#getImage()
でファイル名を指定して画像をファイルから読み込んでいます(10)。
アプレットとして実行されているときは Applet#getImage()
メソッドを使って、getCodeBase()
で得た codeBase
の URL にあるファイル名 face.gif
から画像を読み込んでいます(11)。
(12)は java.awt.MediaTracker
を使った画像読み込みの同期処理です。waitForID()
で、完全に画像が読み込まれるまで待ち続けています。
(13)でテクスチャー画像を読み込ませるための java.awt.image.BufferedImage
を生成しています。テクスチャー画像のサイズは 2n×2n
ピクセルである必要があるので、用意した GIF ファイル face.gif
のサイズは 128×128
ピクセルにしました。BufferedImage
のコンストラクターでも 128×128
ピクセルを指定しています。また、用意した GIF ファイルは透明度を持っています。このため、imageType
(画像形式)には TYPE_INT_ARGB
を指定しています。
(14)で画像をコピーするために、int
配列を宣言して、BufferedImage
から得た画像データの配列で初期化しています。
まずgetRaster()
メソッドで java.awt.image.Raster
オブジェクトを取得し、Raster#getDataBuffer()
メソッドで java.awt.image.DataBuffer
を取得しています。
つぎに DataBuffer
を java.awt.image.DataBufferInt
でキャストして、DataBufferInt#getData()
メソッドで int
配列を取得しています。
(15)で画像データをコピーするために java.awt.image.PixcelGrabber
を生成しています。コンストラクター引数では最初にコピー元になる java.awt.image.Image
を指定し、以下 画像の左上の x座標=0, y座標=0, 画像の幅=123, 高さ=128, コピー先の int
配列、最初のピクセルを格納する配列要素の index=0、画像の1列のピクセル数=128 を指定しています。
(16)でgrabPixcels()
でピクセルのデータを int
型として取り出し、コピー先の配列の各要素に格納しています。
(17)でImageComponent2D
を生成しています。コンストラクター引数には、画像フォーマット ImageComponent.FORMAT_RGBA
と、画像を読み込んだ BufferedImage
を与えています。なお、透明度は TransparencyAttributes
を適用しないと反映されません。
(18)でTexture2D
を生成しています。コンストラクター引数は、MipMap形式に基本レベルテクスチャー Texture.BASE_LEVEL
を、テクスチャーフォーマットとして Texture.RGBA
を、テクスチャーの横幅として 128
、高さとして 128
を指定しています。(19)でsetImage()
メソッドを使ってテクスチャー画像を読み込んだBufferedImage
をTexture2D
にセットしています。
(20)で setTexture()
メソッドを使って Texture2d
を Appearance
に設定しています。
アプリケーションとして実行されたときに使われる main()
メソッドでは、(21)でコンストラクター引数に true
を渡して TextureApplet
を生成しています。
サンプルの実行結果はつぎのようになります。
ポリゴンの頂点に書かれているテクスチャー座標は説明のために記入したもので、画面には表示されません。マウスを使って回転/移動/ズームができるようになっています。
com.sun.j3d.utils.image.TextureLoader
ファイルや URL から画像を読み込んで Texture
を生成するための便利なクラスが com.sun.j3d.utils.image
パッケージに用意されています。TextureLoader
クラスです。
クラス継承 java.lang.Object | +--com.sun.j3d.utils.image.TextureLoader クラス宣言 public class TextureLoader extends java.lang.Object コンストラクター public TextureLoader(java.awt.image.BufferedImage bImage) // テクスチャー画像の BufferedImage public TextureLoader(java.awt.image.BufferedImage bImage, // テクスチャー画像の BufferedIMage java.lang.String format) // 画像フォーマット
BufferedImage
を引数に取るコンストラクターでは ImageComponent2D
と同様に、ファイルから読み込んだ画像を BufferedImage
に保存したり、プログラムから BufferedImage
に描画したりしてテクスチャーのための画像を BufferedImage
に描画しておきます。
format
には画像フォーマットを文字列で指定します。画像フォーマットにはつぎのものがあります。
"RGBA" // 各8ビットの赤、緑、青、不透明度(アルファ値) "RGBA4" // 各4ビットの赤、緑、青、不透明度(アルファ値) "RGB5_A1" // 各5ビットの赤、緑、青と、1ビットの不透明度(アルファ値) "RGB" // 各8ビットの赤、緑、青 "RGB4" // 各4ビットの赤、緑、青 "RGB5" // 各5ビットの赤、緑、青 "R3_G3_B2" // 各3ビットの赤、緑と、2ビットの青 "LUM8_ALPHA8" // 8ビットの光度と、8ビットの不透明度(アルファ値) "LUM4_ALPHA4" // 4ビットの光度と、4ビットの不透明度(アルファ値) "LUMINANCE" // 8ビットの光度 "ALPHA" // 8ビットの不透明度(アルファ値)
Texture
や ImageComponent
で指定する画像フォーマットに似ていますが、TextureLoader
では文字列で指定します。
TextureLoader
では、複数のレベルの MipMap を生成することも出来ます。
public TextureLoader(java.awt.image.BufferedImage bImage, // テクスチャー画像の BuffueredImage int flags) // MipMap 生成フラグ
引数に flags
を取るコンストラクターで GENERATE_MIPMAP
を指定すると、TextureLoader
は複数のレベルの MipMap を生成してくれます。
public static final int GENERATE_MIPMAP // 複数の MipMap を生成する
TextureLoader
には java.awt.image.BufferedImage, java.awt.image.Image, java.net.URL
などの様々なオブジェクトから Texture
を生成するためのコンストラクターが数多く用意されています。java.lang.String
でファイル名を指定するコンストラクターもあります。
public TextureLoader(java.awt.image.BufferedImage bImage, // テクスチャー画像の BufferedImage java.lang.String format, // 画像フォーマット int flags) // MipMap 生成フラグ public TextureLoader(java.awt.Image image, // テクスチャー画像の Image java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.awt.Image image, // テクスチャー画像の Image java.lang.String format, // 画像フォーマット java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.awt.Image image, // テクスチャー画像の Image int flags, // MipMap 生成フラグ java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.awt.Image image, // テクスチャー画像の Image java.lang.String format, // 画像フォーマット int flags, // MipMap 生成フラグ java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.lang.String fname, // テクスチャー画像のファイル名 java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.lang.String fname, // テクスチャー画像のファイル名 java.lang.String format, // 画像フォーマット java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.lang.String fname, // テクスチャー画像のファイル名 int flags, // MipMap 生成フラグ java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.lang.String fname, // テクスチャー画像のファイル名 java.lang.String format, // 画像フォーマット int flags, // MipMap 生成フラグ java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.net.URL url, // テクスチャー画像の URL java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.net.URL url, // テクスチャー画像の URL java.lang.String format, // 画像フォーマット java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.net.URL url, // テクスチャー画像の URL int flags, // MipMap 生成フラグ java.awt.Component observer) // imageUpdate() の通知先 public TextureLoader(java.net.URL url, // テクスチャー画像の URL java.lang.String format, // 画像フォーマット int flags, // MipMap 生成フラグ java.awt.Component observer) // imageUpdate() の通知先
ファイルなどから読み込んで TextureLoader
を生成したら、getTexture()
メソッドを使って Texture
を取得できます。
メソッド (一部) public Texture getTexture() // Texture を取得する
ImageComponent
のところで、テクスチャー画像のサイズは 2n×2n
ピクセルでなければならないと書きましたが、TextureLoader
はこれ以外のサイズの画像も読み込むことができます。
TextureLoader
に読み込まれた画像は 2n×2n
ピクセルに拡大縮小されます。
TextureLoader
を使ったサンプルは次のようになります。
TextureAttributes.java (一部)104 private Appearance createAppearance() { 105 Appearance app = new Appearance(); 106 107 Image image = null; 108 if (this.isStandalone) { ┐ 109 // アプリケーションとして実行されている │ 110 final Toolkit toolkit = Toolkit.getDefaultToolkit(); │ 111 image = toolkit.getImage("face.gif"); │ 112 } else { │ 113 // アプレットとして実行されている │ 114 image = getImage(getCodeBase(), "face.gif"); ├(1) 115 } │ 116 MediaTracker mt = new MediaTracker(this); │ 117 mt.addImage(image, 0); │ 118 mt.checkAll(true); │ 119 try { mt.waitForID(0); } │ catch (InterruptedException e) { e.printStackTrace(); } ┘ 120 121 Texture2D texture2d = (Texture2D)new TextureLoader(image, this).getTexture();...(2) 122 123 app.setTexture(texture2d); 124 125 return app; 126 }
(1)の Image
の読み込みは前のサンプルと同じです。
Texture
の生成は非常に簡単です。(2)で画像を読み込んだ Image
、imageUpdate()
の通知先となるこのアプレット自身 this
をコンストラクター引数に指定して TxuterLoader
を生成し、getTexture()
メソッドで Texture
オブジェクトを取得しています。
実行結果は前のサンプルと同じなので省略します。
TransparencyAttributes
透明度があるテクスチャー画像でも、TransparencyAttributes
を設定していないと透明度が反映されません。
TextureApplet.java (一部)104 private Appearance createAppearance() { 105 Appearance app = new Appearance(); 106 107 Image image = null; 108 if (this.isStandalone) { 109 // アプリケーションとして実行されている 110 final Toolkit toolkit = Toolkit.getDefaultToolkit(); 111 image = toolkit.getImage("face.gif"); 112 } else { 113 // アプレットとして実行されている 114 image = getImage(getCodeBase(), "face.gif"); 115 } 116 MediaTracker mt = new MediaTracker(this); 117 mt.addImage(image, 0); 118 mt.checkAll(true); 119 try { mt.waitForID(0); } catch (InterruptedException e) { e.printStackTrace(); } 120 121 Texture2D texture2d = (Texture2D)new TextureLoader(image, this).getTexture(); 122 123 app.setTexture(texture2d); 124 125 app.setTransparencyAttributes( 126 new TransparencyAttributes(TransparencyAttributes.BLENDED, 0.0f));...(1) 127 128 app.setPolygonAttributes( 129 new PolygonAttributes( PolygonAttributes.POLYGON_FILL, 130 PolygonAttributes.CULL_NONE, 131 0.0f, false) ); 132 133 return app; 134 }
(1)でsetTransparencyAttributes()
を生成しています。透明度の描画モードは TransparencyAttributes.BLENDED
(アルファブレンドで透明度を描画)、透明度は 0.0
(不透明) です。
サンプルの実行結果を見てください。
テクスチャー画像の透明な部分では背景が透過しています。
TransparencyAttributes
で Shape3D
に設定した透明度は 0.0
で不透明ですが、テクスチャーの透明度に完全に置き換えられています。デフォルトでは物体の色、透明度は、テクスチャーの色、透明度によって完全に置き換えられてしまうようになっています。後で説明しますが、テクスチャーと元の色/透明度との混合モードは TextureAttributes
を適用して変更することができます。
PolygonAttributes
を設定してみる)テクスチャーマップした Shape3D
に PolygonAttributes
を設定するとどうなるでしょうか?
PolygonAttributes
で裏面へのカリングを無し(CULL_NONE
)に設定すると裏面にもテクスチャーが描画されます。
TextureApplet.java (一部)128 app.setPolygonAttributes( 129 new PolygonAttributes( PolygonAttributes.POLYGON_FILL, 130 PolygonAttributes.CULL_NONE, 131 0.0f, false) );
ポリゴンをマウスで回転させてみてください。裏面にもテクスチャー描画されています。
WRAP
ポリゴンの頂点に設定されたテクスチャー座標が 0.0〜1.0
の範囲を超えていた場合、デフォルトではテクスチャーは繰り返し適用されます。(WRAP
される)
つぎのサンプルでは、ポリゴンの頂点に-2.0〜+2.0
の範囲のテクスチャー座標を設定しています。
このサンプルのソースは次の通りです。
TextureApplet.java (一部)48 private BranchGroup createSceneGraph() { 49 BranchGroup root = new BranchGroup(); 50 51 Background bg = new Background(new Color3f(0.5f, 0.5f, 0.5f)); 52 bg.setApplicationBounds(new BoundingSphere(new Point3d(), 100.0)); 53 root.addChild(bg); 54 55 TransformGroup trans = new TransformGroup(); 56 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 57 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 58 59 BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0); 60 61 MouseRotate rotator = new MouseRotate(trans); 62 rotator.setSchedulingBounds(bounds); 63 root.addChild(rotator); 64 65 MouseTranslate translator = new MouseTranslate(trans); 66 translator.setSchedulingBounds(bounds); 67 root.addChild(translator); 68 69 MouseZoom zoomer = new MouseZoom(trans); 70 zoomer.setSchedulingBounds(bounds); 71 root.addChild(zoomer); 72 73 Point3d[] vertices = new Point3d[4]; 74 vertices[0] = new Point3d(-0.4, -0.4, 0.0); // 左下 3+-----+2 75 vertices[1] = new Point3d( 0.4, -0.4, 0.0); // 右下 | | 76 vertices[2] = new Point3d( 0.4, 0.4, 0.0); // 右上 | | 77 vertices[3] = new Point3d(-0.4, 0.4, 0.0); // 左上 0+-----+1 78 79 Point2f[] txcoords = new Point2f[4]; ┐ 80 txcoords[0] = new Point2f(-2.0f, -2.0f); // 左下 3+-----+2 │ 81 txcoords[1] = new Point2f( 2.0f, -2.0f); // 右下 | | ├(1) 82 txcoords[2] = new Point2f( 2.0f, 2.0f); // 右上 | | │ 83 txcoords[3] = new Point2f(-2.0f, 2.0f); // 左上 0+-----+1 ┘ 84 85 QuadArray geom = 86 new QuadArray( vertices.length, 87 GeometryArray.COORDINATES | 88 GeometryArray.TEXTURE_COORDINATE_2); 89 geom.setCapability(Geometry.ALLOW_INTERSECT); 90 geom.setCoordinates(0, vertices); 91 geom.setTextureCoordinates(0, txcoords); 92 93 Appearance ap = createAppearance(); 94 95 Shape3D grid = new Shape3D(geom, ap); 96 grid.setCapability(Shape3D.ALLOW_GEOMETRY_READ); 97 trans.addChild(grid); 98 99 root.addChild(trans); 100 101 return root; 102 }
(1)でテクスチャー座標配列を宣言/初期化しています。左下が (-2.0, -2.0)
、右上が (2.0, 2.0)
にしてあります。0.0〜1.0
の範囲を超える部分にはテクスチャーが繰り返し適用されることになります。
CLAMP
0.0〜1.0
のテクスチャー座標の範囲だけにテクスチャーを適用するには、setMagFilter(), setMinFilter()
メソッドを使ってS座標方向、T座標方向へのテクスチャー境界の形式を Texture.CLAMP
に設定します。
TextureApplet.java (一部)104 private Appearance createAppearance() { 105 Appearance app = new Appearance(); 106 107 Image image = null; 108 if (this.isStandalone) { 109 // アプリケーションとして実行されている 110 final Toolkit toolkit = Toolkit.getDefaultToolkit(); 111 image = toolkit.getImage("face.gif"); 112 } else { 113 // アプレットとして実行されている 114 image = getImage(getCodeBase(), "face.gif"); 115 } 116 MediaTracker mt = new MediaTracker(this); 117 mt.addImage(image, 0); 118 mt.checkAll(true); 119 try { mt.waitForID(0); } catch (InterruptedException e) { e.printStackTrace(); } 120 121 Texture2D texture2d = (Texture2D)new TextureLoader(image, this).getTexture(); 122 texture2d.setMagFilter(Texture.BASE_LEVEL_LINEAR); ┐ 123 texture2d.setMinFilter(Texture.BASE_LEVEL_LINEAR); ├(1) 124 texture2d.setBoundaryModeS(Texture.CLAMP); │ 125 texture2d.setBoundaryModeT(Texture.CLAMP); ┘ 126 app.setTexture(texture2d); 127 128 return app; 129 }
(1)でsetMagFilter(), setMinFilter()
を使って、拡大縮小フィルターを Texture.BASE_LEVEL_LIEAR
に設定しています。この場合、0.0〜1.0
の範囲外での色はテクスチャーの外周のピクセルの色が加重平均されたものが適用されます。
拡大縮小フィルターを Texture.BASE_LEVEL_POINT
に設定すると、テクスチャーの外周のピクセルの色が繰り返し使われます。
javax.media.j3d.TexCoordGeneration
ポリゴンの頂点に明示的にテクスチャー座標を指定する方法のほかに、テクスチャー座標生成平面と呼ばれるものや物体の法線ベクトルを利用してテクスチャー座標を生成することができます。このためのクラスが javax.media.j3d.TexCoordGeneration
です。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.TexCoordGeneration クラス宣言 public class TexCoordGeneration extends NodeComponent コンストラクター public TexCoordGeneration() public TexCoordGeneration(int genMode, // テクスチャー座標生成モード int format) // テクスチャー形式(2次元または3次元)
TexCoordGeneration
のコンストラクターでは、引数 genMode
にテクスチャー座標の生成モードを指定します。テクスチャー座標生成モードには次のものがあります。
public static final int OBJECT_LINEAR // オブジェクト座標に従ってテクスチャー座標を生成 public static final int EYE_LINEAR // 視点座標に従ってテクスチャー座標を生成 public static final int SPHERE_MAP // 球体反射マッピングを使用してテクスチャー座標を生成
genMode
に OBJECT_LINEAR
を指定すると、テクスチャー座標はオブジェクト座標に従います。物体を回転/移動すると、テクスチャーは物体の表面に固定され回転/移動に従います。
EYE_LINEAR
を指定するとテクスチャーは視点座標に従います。テクスチャーは視点座標に固定され、物体に投影されたようになります。物体を回転/移動してもテクスチャーは視点に固定されたままです。物体はテクスチャーの中を回転/移動するように見えます。
SPHERE_MAP
は鏡や金属の表面のように、周囲のものを反射する物体の描画に使用します。これを球体反射マッピングと呼びます。
このとき魚眼レンズで撮影した写真のようなテクスチャーが必要になります。テクスチャーは物体の周囲の球体の内側に適用されているような状態になり、物体の表面には周囲のテクスチャーを反射しているような画像が適用されます。
Java 3D ではレイトレーシングのような光線の反射計算は行われません。このため鏡や金属の表面のようなものを描画する機能はありませんが、球体反射マッピングで鏡や金属の表面のような効果が得られます。
コンストラクター引数の format
には、2次元テクスチャーか3次元テクスチャーかの別を指定します。
public static final int TEXTURE_COORDINATE_2 // 2次元テクスチャー public static final int TEXTURE_COORDINATE_3 // 3次元テクスチャー
テクスチャー座標は、テクスチャー座標生成平面というものを指定して生成します。2次元テクスチャーでは S平面、T平面を、3次元テクスチャーでは S, T, R
の3平面を指定します。
public TexCoordGeneration(int genMode, // テクスチャー座標生成モード int format, // テクスチャー形式(2次元または3次元) Vector4f planeS) // S座標の平面方程式 public TexCoordGeneration(int genMode, // テクスチャー座標生成モード int format, // テクスチャー形式(2次元または3次元) Vector4f planeS, // S座標の平面方程式 Vector4f planeT) // T座標の平面方程式 public TexCoordGeneration(int genMode, // テクスチャー座標生成モード int format, // テクスチャー形式(2次元または3次元) Vector4f planeS, // S座標の平面方程式 Vector4f planeT, // T座標の平面方程式 Vector4f planeR) // R座標の平面方程式
テクスチャー座標生成平面は平面方程式を使って指定します。平面方程式は面法線ベクトルを使って表現します。
平面方程式のデフォルト値は次の通りです。
plane S : (1,0,0,0) plane T : (0,1,0,0) plane R : (0,0,0,0)
デフォルト値の S平面は X=0
の YZ平面、デフォルト値の T平面は Y=0
の XZ平面になるようです。
テクスチャー座標は、テクスチャー座標生成平面からポリゴンの頂点までの距離によって決定されます。
genMode
に OBJECT_LINEAR
を指定したとき、テクスチャー座標生成平面はオブジェクト座標に従います。テクスチャー座標生成平面はオブジェクト座標に固定されたようになり、物体を回転/移動するとテクスチャー座標生成平面も回転/移動します。
genMode
に EYE_LINEAR
を指定すると、テクスチャー座標生成平面は視点座標に従います。物体を回転/移動してもテクスチャー座標生成平面は回転/移動しません。
genMode
に SPHERE_MAP
を指定したとき、テクスチャー座標の計算にはテクスチャー座標生成平面を使用しません。テクスチャー座標は物体の法線ベクトルを使って計算します。このとき物体の Geometry
には頂点法線ベクトルの設定が必要です。
テクスチャーは半球として扱われます。法線が各頂点からテクスチャー球体に投影され、その点の色を使って物体が描画されます。
テクスチャーが半球として扱われるので、魚眼レンズで撮影したようなテクスチャー画像が必要になります。
TexCoordGeneration
の使用方法は次の通りです。
TexCoordGeneration
を生成するAppearance#setTexCoordGeneration()
メソッドで Appearance
に設定するAppearance
を物体 (Shape3D
など) に設定するOBJECT_LINEAR
のサンプルOBJECT_LINEAR
のサンプルのソースはつぎのようになっています。
TexGenTest.java (一部)217 private Appearance createAppearance() { 218 Appearance app = new Appearance(); 219 220 Image image = null; 221 if (this.isStandalone) { 222 // アプリケーションとして実行されている 223 final Toolkit toolkit = Toolkit.getDefaultToolkit(); 224 image = toolkit.getImage("face.gif"); 225 } else { 226 // アプレットとして実行されている 227 image = getImage(getCodeBase(), "face.gif"); 228 } 229 MediaTracker mt = new MediaTracker(this); 230 mt.addImage(image, 0); 231 mt.checkAll(true); 232 try { mt.waitForID(0); } catch (InterruptedException e) { e.printStackTrace(); } 233 234 Texture2D texture2d = (Texture2D)new TextureLoader(image, this).getTexture(); 235 236 app.setTexture(texture2d); 237 238 texgen = ┐ 239 new TexCoordGeneration( TexCoordGeneration.OBJECT_LINEAR,....................(2) │ 240 TexCoordGeneration.TEXTURE_COORDINATE_2,.............(3) ├(1) 241 new Vector4f(1.0f, 0.0f, 0.0f, 0.0f), // PlaneS ...(4) │ 242 new Vector4f(0.0f, 1.0f, 0.0f, 0.0f) ); // PlaneT ...(5) │ 243 app.setTexCoordGeneration(texgen); ┘ 244 245 return app; 246 }
テクスチャーを適用するのは、(0.0, 0.0, 0.0)〜(1.0, 1.0, -1.0)
の大きさの立方体です。立方体の辺、テクスチャー生成平面に置く平面ポリゴン、座標軸となる LineArray
を描画しています。
(1)で TexCoordGeneration
を生成しています。
(2)でテクスチャー座標生成モードとして TexCoordGeneration.OBJECT_LINEAR
を指定しています。テクスチャー座標生成平面はオブジェクト座標に従います。
(3)で2次元テクスチャー座標を生成させるために TexCoordGeneration.TEXTURE_COORDINATE_2
を指定しています。
(4)でS座標のテクスチャー生成平面方程式 (1.0, 0.0, 0.0, 0.0)
を指定しています。ここでは X=0 の YZ平面を定義しています。
(5)でT座標のテクスチャー生成平面方程式 (0.0, 1.0, 0.0, 0.0)
を指定しています。ここでは Y=0 の XZ平面を定義しています。
サンプルの実行結果を見てください。
S座標方向のテクスチャー座標は、S座標のテクスチャー座標生成平面から、ポリゴンの頂点までの距離になります。サンプルではS座標方向のテクスチャー座標生成平面の位置 (X=0のYZ平面) に透明な赤の平面ポリゴンを置いてあります。このサンプルでは最も近い頂点までの距離が 0.0
、最も遠い頂点までの距離が 1.0
になっています。
T座標方向のテクスチャー座標は、T座標のテクスチャー座標生成平面から、ポリゴンの頂点までの距離になります。サンプルではT座標方向のテクスチャー座標生成平面の位置 (Y=0のXZ平面) に透明な緑の平面ポリゴンを置いてあります。このサンプルでは S座標の場合と同様に、最も近い平面までの距離が 0.0
、最も遠い頂点までの距離が 1.0
になっています。
マウスで物体を回転させてみてください。テクスチャーは物体の座標系 (オブジェクト座標) に従います。
EYE_LINEAR
のサンプルテクスチャー座標生成モードを EYE_LINEAR
に設定すると、テクスチャー座標生成平面は常に視点座標に従います。
サンプルのソースは次のようになっています。
TexGenTest.java (一部)176 private Appearance createAppearance() { 177 Appearance app = new Appearance(); 178 179 Image image = null; 180 if (this.isStandalone) { 181 // アプリケーションとして実行されている 182 final Toolkit toolkit = Toolkit.getDefaultToolkit(); 183 image = toolkit.getImage("face.gif"); 184 } else { 185 // アプレットとして実行されている 186 image = getImage(getCodeBase(), "face.gif"); 187 } 188 MediaTracker mt = new MediaTracker(this); 189 mt.addImage(image, 0); 190 mt.checkAll(true); 191 try { mt.waitForID(0); } catch (InterruptedException e) { e.printStackTrace(); } 192 193 Texture2D texture2d = (Texture2D)new TextureLoader(image, this).getTexture(); 194 195 app.setTexture(texture2d); 196 197 TexCoordGeneration texgen = ┐ 198 new TexCoordGeneration( TexCoordGeneration.EYE_LINEAR, ...............(2) │ 199 TexCoordGeneration.TEXTURE_COORDINATE_2, ├(1) 200 new Vector4f(1.0f, 0.0f, 0.0f, 0.0f), // PlaneS │ 201 new Vector4f(0.0f, 1.0f, 0.0f, 0.0f) ); // PlaneT │ 202 app.setTexCoordGeneration(texgen); ┘ 203 204 return app; 205 }
テクスチャーを適用する立方体は前のサンプルと同じです。
テクスチャー座標生成平面は視点座標に固定されているので、テクスチャー座標生成平面の位置を示す平面ポリゴンは省略しました。
Z座標の座標軸は描画しても見えないので省略しました。マウスで立方体を回転させても、XY座標の座標軸は回転しないようにしてあります。
(1)で TexCoordGeneration
を生成しています。前のサンプルとの違いは、(2)のテクスチャー座標生成モードが EYE_LINEAR
になっている点だけです。
サンプルの実行結果を見てください。
マウスの右ボタンドラッグで物体を移動させると、物体はテクスチャーの中を移動するように見えます。
SHPERE_MAP
のサンプルテクスチャー座標生成モードに SPHERE_MAP
を指定すると球体反射マッピングが適用されます。
サンプルソースは次の通りです。
TexGenTest.java53 private BranchGroup createSceneGraph() { 54 BranchGroup root = new BranchGroup(); 55 root.setCapability(BranchGroup.ALLOW_DETACH); 56 57 Bounds bounds = new BoundingSphere(new Point3d(), 100.0); 58 59 Light light = new DirectionalLight(); 60 light.setInfluencingBounds(bounds); 61 root.addChild(light); 62 63 Background bg = new Background(new Color3f(0.5f, 0.5f, 0.5f)); 64 bg.setApplicationBounds(bounds); 65 root.addChild(bg); 66 67 TransformGroup trans = new TransformGroup(); 68 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 69 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 70 71 MouseRotate rotator = new MouseRotate(trans); 72 rotator.setSchedulingBounds(bounds); 73 root.addChild(rotator); 74 75 MouseTranslate translator = new MouseTranslate(trans); 76 translator.setSchedulingBounds(bounds); 77 root.addChild(translator); 78 79 MouseZoom zoomer = new MouseZoom(trans); 80 zoomer.setSchedulingBounds(bounds); 81 root.addChild(zoomer); 82 83 Appearance ap = createAppearance(); 84 85 Cone cone = new Cone( 0.5f, 1.0f, Primitive.GENERATE_NORMALS, ap );...(1) 86 trans.addChild(cone); 87 88 root.addChild(trans); 89 90 return root; 91 } 92 93 private Appearance createAppearance() { 94 Appearance app = new Appearance(); 95 96 Image image = null; 97 if (this.isStandalone) { 98 // アプリケーションとして実行されている 99 final Toolkit toolkit = Toolkit.getDefaultToolkit(); 100 image = toolkit.getImage("fisheye.jpg"); 101 } else { 102 // アプレットとして実行されている 103 image = getImage(getCodeBase(), "fisheye.jpg"); 104 } 105 MediaTracker mt = new MediaTracker(this); 106 mt.addImage(image, 0); 107 mt.checkAll(true); 108 try { mt.waitForID(0); } catch (InterruptedException e) { e.printStackTrace(); } 109 110 Texture2D texture2d = (Texture2D)new TextureLoader(image, this).getTexture(); 111 112 app.setTexture(texture2d); 113 114 TexCoordGeneration texgen = ┐ 115 new TexCoordGeneration( TexCoordGeneration.SPHERE_MAP,...........(3) ├(2) 116 TexCoordGeneration.TEXTURE_COORDINATE_2 ); │ 117 app.setTexCoordGeneration(texgen); ┘ 118 119 return app; 120 }
テクスチャー座標は法線ベクトルを使って計算されるため、(1)で Primitive.GENERATE_NORMALS
を指定して法線ベクトルを生成しています。
(2)で TexCoordGeneration
を生成しています。テクスチャー座標は頂点法線を使って計算されるのでテクスチャー座標生成平面の平面方程式は設定していません。
(3)でテクスチャー座標生成モードに SPHERE_MAP
を指定しています。
サンプルの実行結果は次のようになります。
物体の表面には投影されたテクスチャーで、鏡や金属の表面のように周囲を反射しているように見えます。マウスで物体を回転させてみてください。物体の位置に応じて周囲を反射しているようにテクスチャーが適用されます。
javax.media.j3d.TetxureAttributes
javax.media.j3d.TetxureAttributes
クラスを使うと、テクスチャーが持つ色や透明度と物体に適用されている Material
や透明度とを様々なモードで混合させることができます。また、テクスチャーを回転させたり、遠近に応じた補正のモードを設定することができます。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.TextureAttributes クラス継承 public class TextureAttributes extends NodeComponent コンストラクター public TextureAttributes() public TextureAttributes(int textureMode, // テクスチャーモード Transform3D transform, // テクスチャー座標の座標軸 Color4f textureBlendColor, // テクスチャー混合色 int perspCorrectionMode) // 遠近法補正モード
textureMode
には次の定数値を指定できます。
定数フィールド public static final int MODULATE // オブジェクトの色をテクスチャーの色で調整する public static final int DECAL // テクスチャーの色をデカール表面色としてオブジェクトに適用する public static final int BLEND // テクスチャーの色をオブジェクトの色と混合する public static final int REPLACE // オブジェクトの色をテクスチャーの色に置き換える
textureMode
に MODELATE
を指定するとテクスチャーの色が物体の色に混合されます。
物体の Material
に設定された specularColor
(鏡面反射による色) は、テクスチャーの影響を受けずに最後に適用されます。
DECAL
を指定すると物体の表面にテクスチャーが張り付けられ、テクスチャーが適用されない部分には元の物体の色が残されます。例えば背景が透明なテクスチャーを使用すれば、透明な部分にはもとの物体の色が残ります。テクスチャーが不透明な部分では物体の色はテクスチャーの色で完全に置き換えられます。テクスチャーが不透明な部分には specularColor
の影響もありません。
BLEND
を指定すると、テクスチャーはまず textureBlendColor
と混合されます。つぎに MODULATE
と同様に物体の表面色と混合されます。
REPLATE
を指定すると、物体の表面色はテクスチャーの色で完全に置き換わります。
transform
に指定した Transform3D
に回転/移動/拡大縮小を適用すると、テクスチャーを回転/移動/拡大縮小させることができます。
perspCorrectionMode
には遠近法補正モードを指定します。遠近法補正モードはつぎの2つです。
public static final int FASTEST // 可能な限り高速に遠近法補正を行う public static final int NICEST // 可能な限り高品質に遠近法補正を行う
TextureAttributes
の使用方法は次の通りです。
TextureAttributes
を生成するAppearance#setTextureAttributes()
メソッドで Appearance
に設定するAppearance
を物体 (Shape3D
など) に設定するサンプルの実行結果は次のようになります。
テクスチャーを適用する球体と、テクスチャー座標生成平面の位置の平面ポリゴン、オブジェクト座標の座標軸を表す LineArray
を描画しています。
球体はマウスで回転/移動/ズームすることができます。
ウインドウ上部左の Choice
でテクスチャー混合モードを MODULATE, DECAL, BLEND, REPLACE
に切替えることができます。ウインドウ上部右の FASTEST, NICEST
に切替えられます。
ウインドウ上部の TuplePanel
で RGBA を入力してテクスチャー混合色を変更できます。このサンプルではテクスチャー混合色のデフォルト値を不透明な赤に設定しています。
ウインドウ上部下段の TextField
にZ軸を中心とした回転角を入力すると、テクスチャー座標を回転させることができます。回転角に入力した数値にπを乗じた値が回転角に設定されます。
画面下部の TuplePanel
で RGBA を入力して diffuseColor
を変更することができます。このサンプルではデフォルトの diffuseColor
を青に設定しています。
画面下部下段の TextField
に透明度を入力して透明度を変更することができます。その右の Choice
で透明度の描画モードを変更することができます。
テクスチャーの混合モードと、物体の色、透明度をいろいろ変化させて、どのように描画されるか確かめてください。
サンプルのソースは次の通りです。
TextureAttributesTest.java (一部)1 // Java 3D Test Applet 2 // TextureAttributesTest.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 javax.media.j3d.*; 11 import javax.vecmath.*; 12 import com.sun.j3d.utils.applet.MainFrame; 13 import com.sun.j3d.utils.universe.SimpleUniverse; 14 import com.sun.j3d.utils.geometry.Primitive; 15 import com.sun.j3d.utils.geometry.Sphere; 16 import com.sun.j3d.utils.image.TextureLoader; 17 import com.sun.j3d.utils.behaviors.mouse.MouseRotate; 18 import com.sun.j3d.utils.behaviors.mouse.MouseTranslate; 19 import com.sun.j3d.utils.behaviors.mouse.MouseZoom; 20 21 public class TextureAttributesTest extends Applet { 22 private Canvas3D canvas = null; 23 private Texture texture = null; 24 private TextureAttributes txattr = null; 25 private Color4f blendcolor = new Color4f(1.0f, 0.0f, 0.0f, 1.0f); // 赤 ...(1) 26 private Transform3D txtrans = new Transform3D(); 27 private Material mat = null; 28 private Color3f diffusecolor = new Color3f(0.0f, 0.0f, 1.0f); // 青 29 private TransparencyAttributes tattr = null; 30 private TexCoordGeneration texgen = null; : : 299 private Appearance createAppearance() { 300 Appearance app = new Appearance(); 301 302 // Texture の生成 303 Image image = null; 304 if (this.isStandalone) { 305 // アプリケーションとして実行されている 306 Toolkit toolkit = Toolkit.getDefaultToolkit(); 307 image = toolkit.getImage("face.gif"); 308 } else { 309 // アプレットとして実行されている 310 image = getImage(getCodeBase(), "face.gif"); 311 } 312 MediaTracker mt = new MediaTracker(this); 313 mt.addImage(image, 0); 314 mt.checkAll(true); 315 try { mt.waitForID(0); } catch (InterruptedException e) { e.printStackTrace(); } 316 texture = new TextureLoader(image, this).getTexture(); 317 texture.setBoundaryModeS(Texture.CLAMP); 318 texture.setBoundaryModeT(Texture.CLAMP); 319 app.setTexture(texture); 320 321 txattr = new TextureAttributes();.....................................(2) 322 txattr.setCapability(TextureAttributes.ALLOW_BLEND_COLOR_READ); ┐ 323 txattr.setCapability(TextureAttributes.ALLOW_BLEND_COLOR_WRITE); │ 324 txattr.setCapability(TextureAttributes.ALLOW_MODE_READ); ├(3) 325 txattr.setCapability(TextureAttributes.ALLOW_MODE_WRITE); │ 326 txattr.setCapability(TextureAttributes.ALLOW_TRANSFORM_READ); │ 327 txattr.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE); ┘ 328 txattr.setTextureBlendColor(blendcolor); // BLEND にしないと反映されない ...(4) 329 txattr.setTextureTransform(txtrans);...................................(5) 330 app.setTextureAttributes(txattr);......................................(6) 331 332 mat = new Material(); 333 mat.setCapability(Material.ALLOW_COMPONENT_READ); 334 mat.setCapability(Material.ALLOW_COMPONENT_WRITE); 335 mat.setDiffuseColor(diffusecolor); 336 app.setMaterial(mat); 337 338 tattr = new TransparencyAttributes(); 339 tattr.setCapability(TransparencyAttributes.ALLOW_VALUE_READ); 340 tattr.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE); 341 tattr.setCapability(TransparencyAttributes.ALLOW_MODE_READ); 342 tattr.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE); 343 app.setTransparencyAttributes(tattr); 344 345 texgen = 346 new TexCoordGeneration( TexCoordGeneration.OBJECT_LINEAR, 347 TexCoordGeneration.TEXTURE_COORDINATE_2, 348 new Vector4f(1.0f, 0.0f, 0.0f, 0.0f), 349 new Vector4f(0.0f, 1.0f, 0.0f, 0.0f) ); 350 app.setTexCoordGeneration(texgen); 351 352 return app; 353 }
(2)で TextureAttiributes
を生成しています。
実行時にテクスチャー混合モード、テクスチャー混合色、
テクスチャー座標軸を変更したいので、
(3)でそれぞれの capability bit
をセットしています。
(4)でテクスチャー混合色を設定しています。テクスチャー混合色は (1)で不透明な赤色として宣言した Color4f
オブジェクトでです。
(5)ではテクスチャーの座標軸となる Transform3D
を設定しています。
(6)で setTextureAttributes()
メソッドを使って、TextureAttributes
を Appearance
に設定しています。
javax.media.j3d.Texture3D
javax.media.j3d.Texture3D
は3次元テクスチャーのためのクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.Texture | +--javax.media.j3d.Texture3D クラス宣言 public class Texture3D extends Texture コンストラクター public Texture3D() public Texture3D(int mipmapMode, // MipMap形式 int format, // 画像フォーマット int width, // 幅 int height, // 高さ int depth) // 奥行き
コンストラクターでは、幅、高さに加えて3次元テクスチャーの奥行きを指定します。
mipMapMode, format
は Texture
クラスと同様です。
Texture3D
には、ポリゴンの頂点に設定した R座標が 0.0〜1.0
の範囲を超えたときに、0.0〜1.0
の範囲だけにテクスチャーを適用するか、それともテクスチャーを繰り返し適用するかを設定するメソッドを持ちます。setBoundaryModeR()
メソッドです。
メソッド (一部) public final void setBoundaryModeR(int boundaryModeR) // R座標方向の境界形式
setBoundaryModeR()
メソッドの引数は setBoundaryModeS(), setBoundaryModeT()
と同様に CLAMP
または WRAP
です。
CLAMP
を指定するとテクスチャーは 0.0〜1.0
の範囲だけに適用され、WRAP
を指定するとテクスチャーは繰り返し適用されます。デフォルトは WRAP
です。
なお、OpenGL 1.1 には3次元テクスチャーについての仕様が無いため、Win32 の OpenGL 1.1 実装にも3次元テクスチャーはありません。このため、Java 3D の Texture3D
も Win32 では正常に動作しません。
Solaris の OpenGL 1.1.1 や Linux の Mesa 3.0.2 では独自の拡張がされているため、3次元テクスチャーが使用できます。Java 3D もこれらとの組合せで Texture3D
を動作させることができます。
javax.media.j3d.ImageComponent3D
javax.media.j3d.ImageComponent3D
は3次元テクスチャーのための複数の画像を保持するクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.ImageComponent | +--javax.media.j3d.ImageComponent3D クラス宣言 public class ImageComponent3D extends ImageComponent コンストラクター (一部) public ImageComponent3D(int format, // 画像フォーマット java.awt.image.BufferedImage[] images) // 奥行きに応じた BufferedImage配列 メソッド (一部) public final void set(java.awt.image.BufferedImage[] images) // 奥行きに応じた BufferedImage 配列 public final void set(int index, // 奥行きの index java.awt.image.BufferedImage image) // テクスチャー画像の BufferedImage
ImageComponent3D
には BufferedImage
の配列を設定します。BufferedImage
の配列は先頭要素 (index = 0
) が R座標のゼロになります。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
に変更できます。
初期状態では ポリゴンの面が描画されています(POLYGON_FILL
モード)。ウインドウ上部の Choice
を使って、ポリゴンの辺の描画 (POLYGON_LINE
)や、ポリゴンの頂点の描画 (POLYGON_POINT
) に切替えることができます。
初期状態ではポリゴンの裏面は描画されません(CULL_BACK
モード)。ウインドウ上部の Choice
を使って、表面を描画しない(CULL_FRONT
)、両方の面を描画する(CULL_NONE
)、などのモードに切替えることができます。
条件をいろいろ変更して試してみてください。このサンプルのソースコードは次の通りです。
Texture3DTest.java (一部)265 private Appearance createAppearance() { 266 Appearance app = new Appearance(); 267 268 BufferedImage[] bimages = new BufferedImage[64];...(1) 269 270 float dh = 1.0f / 64.0f; ................................................(3) ┐ 271 for (int i=0; i<64; i++) { │ 272 bimages[i] = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);...(4) │ 273 Graphics g = (Graphics)bimages[i].createGraphics();....................(5) │ 274 g.fillRect(0, 0, 64, 64); │ 275 float h = dh * (float)i; │ 276 Color c = Color.getHSBColor(h, 1.0f, 1.0f);//年輪の色 ├(2) 277 g.setColor(c); │ 278 for (int j=0; j<8; j++) { .............................................(6) │ 279 int x = j * 4; │ 280 int w = 64 - x * 2; │ 281 System.out.println("i=" + i + ", j=" + j + ", x=" + x + ", w=" + w + ", h" + h);//DEBUG 282 g.drawOval(x, x, w, w); .............................................(7) │ 283 } │ 284 } ┘ 285 286 ImageComponent3D icompo3d = 287 new ImageComponent3D(ImageComponent.FORMAT_RGBA, bimages); ....(8) 288 289 Texture3D texture3d = 290 new Texture3D(Texture.BASE_LEVEL, Texture.RGBA, 64, 64, 64); ...(9) 291 texture3d.setImage(0, icompo3d);..................................(10) 292 293 app.setTexture(texture3d);........................................(11) 294 295 txattr = new TextureAttributes();.................................(12) 296 txattr.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE); 297 txattr.setTextureMode(TextureAttributes.FASTEST); 298 Transform3D t3d = new Transform3D();..............................(13) 299 t3d.rotX(Math.PI / 2.0);..........................................(14) 300 txattr.setTextureTransform(t3d);..................................(15) 301 app.setTextureAttributes(txattr); 302 303 texgen = 304 new TexCoordGeneration( TexCoordGeneration.EYE_LINEAR, 305 TexCoordGeneration.TEXTURE_COORDINATE_3 ); ...(16) 306 texgen.setCapability(TexCoordGeneration.ALLOW_MODE_READ); 307 texgen.setPlaneS(new Vector4f(1.0f, 0.0f, 0.0f, 0.0f)); ┐ 308 texgen.setPlaneT(new Vector4f(0.0f, 1.0f, 0.0f, 0.0f)); ├(17) 309 texgen.setPlaneR(new Vector4f(0.0f, 0.0f, 1.0f, 0.0f)); ┘ 310 app.setTexCoordGeneration(texgen);......................................(18) 311 312 pattr = new PolygonAttributes();........................................(19) 313 pattr.setCapability(PolygonAttributes.ALLOW_MODE_WRITE); 314 pattr.setCapability(PolygonAttributes.ALLOW_CULL_FACE_WRITE); 315 app.setPolygonAttributes(pattr);........................................(20) 316 317 return app; 318 }
(1)で BufferedImage
の配列を生成しています。今回は 64×64
ピクセルの BufferedImage
を 64層使用することにします。テクスチャーの縦、横のサイズは 必ず2n のピクセル数である必要があります。
(2)で3次元テクスチャーの元になるグラフィックを BufferedImage
に描画しています。色の生成は HSB で行っています。(3)で、ループごとの色相値の増加分を計算しています。(4)で 64×64
ピクセルの BufferedImage
のインスタンスを生成し、(5)で Color#getHSBColor()
メソッドを使って Color
オブジェクトを生成しています。
各層ごとに 8つの同心円を描くため、(6)の for
ループを使用しています。(7)で Graphics#drawOval()
メソッドを使って円を描画しています。
(8)で javax.media.j3d.ImageComponent3D
を生成しています。コンストラクターの引数として、64×64ピクセル×64層の BufferedImage
を指定しています。
(9)で javax.media.j3d.Texture3D
を生成しています。width, height, depth
はすべて 64
です。
(10)でsetImage()
メソッドを使って Texture3D
に ImageComponent3D
を設定しています。
(11)でsetTexture()
メソッドを使って javax.media.j3d.Appearance
に Texture3D
を設定しています。
テクスチャーに回転を与えるため、TextureAttributes#setTextureTransform()
メソッドを使用しています。
(12)で TextureAttributes
オブジェクトを生成しています。(13)で javax.media.j3d.Transform3D
を生成し、(14)で rotX()
メソッドを使って X軸を回転中心に π/2
ラジアン (90°) 回転させています。回転を与えた Transform3D
は、(15)で setTextureTransform()
メソッドを使って TextureAttributes
に設定されています。
(16)で javax.media.j3d.TexCoordGeneration
を生成しています。テクスチャー座標は s, t, r
の3次元座標です。
(17)で S, T, R
各座標の平面方程式を設定しています。
(18)で setTexCoordGeneration()
メソッドを使って TexCoordGeneration
を Appearance
に設定しています。
(19)でjavax.media.j3d.PolygonAttributes
を生成し、(20)で setPolygonAttributes()
メソッドを使って Appearance
に設定しています。
最後に繰り返しますが、現時点では3次元テクスチャーは Win32 では動作しません。
javax.media.j3d.Rastar
javax.media.j3d.Rastar
は、画像や深度値をシーンに書き込んだり、描画されている色、深度値を読み取ったりするためのクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.Geometry | +--javax.media.j3d.Raster クラス宣言 public class Raster extends Geometry コンストラクター public Raster() public Raster(Point3f pos, // 左上位置 int type, // 形式 int xOffset, // 画像のコピー開始オフセット X int yOffset, // 画像のコピー開始オフセット Y int width, // 幅 (ピクセル) int height, // 高さ (ピクセル) ImageComponent2D image, // 画像が格納された ImageComponent2D DepthComponent depthComponent) // 深度値を設定するための DepthComponent public Raster(Point3f pos, // 左上位置 int type, // 形式 java.awt.Point offset, // 画像のコピー開始オフセット XY java.awt.Dimension size, // 画像の大きさ (幅、高さ) ImageComponent2D image, // 画像が格納された ImageComponent2D DepthComponent depthComponent) // 深度値を設定するための DepthComponent 定数フィールド (一部) public static final int RASTER_COLOR // Raster に色を含む public static final int RASTER_DEPTH // Raster に深度値を含む public static final int RASTER_COLOR_DEPTH // Raster に色と深度値を含む
Raster
は Geometry
のサブクラスです。画像などを設定した Raster
は Shape3D
などに設定して使用します。
コンストラクターでは、Raster
の左上の位置座標、色/深度値/色と深度値 のどれか、画像のコピーを開始するオフセット (X,Y)、画像の大きさ (幅、高さ)、画像を格納してある ImageComponent2D
、深度値を格納してある DepthComponent
を指定します。
本書ではイミディエイト・モードには触れないので、Raster を使ったイメージバッファーの読み取りについては解説しません。
Raster
の使い方は次のようになります。
ImageComponent2D
に画像を読み込むDepthComponent
に深度値を設定するImageComponent2D, DepthComponent
などをコンストラクター引数にして Raster
を生成するRaster
をコンストラクターの引数にして Shape3D
を
生成するShape3D
をシーングラフに addChild()
するサンプルの実行結果を見てください。
マウスで回転/移動/ズームができるようになっています。回転/ズームはやっても効果ありません。回転してもRaster
は常に視点方向を向いています。また、Z座標を変更しても大きさは変わりません。
元の画像には透明度が含まれているので、TransparencyAttributes
で BLENDED, FASTEST, NICEST
を選ぶと Raster
に透明度が適用されます。
TransparencyAttributes
の透明度の値も変更できますが、変更しても変化ありません。常に元の画像の透明度が使用されます。
サンプルのソースは次のようになっています。
RasterTest.java89 private BranchGroup createSceneGraph() { 90 BranchGroup root = new BranchGroup(); 91 92 TransformGroup trans = new TransformGroup(); 93 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 94 trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 95 trans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); 96 97 BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0); 98 99 MouseRotate rotator = new MouseRotate(trans); 100 rotator.setSchedulingBounds(bounds); 101 root.addChild(rotator); 102 103 MouseTranslate translator = new MouseTranslate(trans); 104 translator.setSchedulingBounds(bounds); 105 root.addChild(translator); 106 107 MouseZoom zoomer = new MouseZoom(trans); 108 zoomer.setSchedulingBounds(bounds); 109 root.addChild(zoomer); 110 111 ImageComponent2D image = readImage(); 112 113 Raster raster = new Raster( new Point3f(0.0f, 0.0f, 0.0f), 114 Raster.RASTER_COLOR, 115 0, 0, 128, 128, 116 image, null );..................(1) 117 Appearance app = createAppearance(); 118 Shape3D shape = new Shape3D(raster, app);...................(2) 119 shape.setCapability(Shape3D.ENABLE_PICK_REPORTING); 120 shape.setBounds(new BoundingSphere(new Point3d(), 0.5)); 121 trans.addChild(shape);......................................(3) 122 123 root.addChild(trans); 124 125 return root; 126 } 127 128 private ImageComponent2D readImage() { 129 130 Image image = null; 131 if (this.isStandalone) { 132 // アプリケーションとして実行されている 133 Toolkit toolkit = Toolkit.getDefaultToolkit(); 134 image = toolkit.getImage("face.gif"); 135 } else { 136 // アプレットとして実行されている 137 image = getImage(getCodeBase(), "face.gif"); 138 } 139 140 MediaTracker mt = new MediaTracker(this); 141 mt.addImage(image, 0); 142 mt.checkAll(true); 143 try { mt.waitForID(0); } catch (InterruptedException e) { e.printStackTrace(); } 144 145 TextureLoader tr = new TextureLoader(image, this); 146 147 return tr.getImage(); 148 }
(1)で Raster
を生成しています。形式は RASTER_COLOR
で色データのみ、オフセットは (0, 0)
、サイズは元の画像と同じ (128, 128)
にしました。画像を読み込んだ ImageComponent2D
を指定し、DepthComponent
は使わないので null
を指定しています。
(2)で Raster
をコンストラクター引数に Shape3D
を生成しています。この Shape3D
を(3)で TransformGroup
に addChild()
しています。
ImageComponent2D
への画像の読み込みは TextureLoader
を使っています。読み込み後 TextureLoader#getImage()
で ImageComponent2D
を取得しています。
Raster
はポリゴンを生成する必要が無いので、テクスチャーマッピングよりも資源が少なくて済むようです。ただし、Z座標を変えても大きさが変わらない、回転させても常に同じ方向を向いている、などの特徴があります。
本書では説明しませんが、イミディエイト・モードで Canvas3D
が描画したイメージを取得するときにも Raster
を使用します。