Appearance
の効果(透明度、点の大きさ、線の太さ、など)javax.media.j3d.Material
のところで少し触れましたが、javax.media.j3d.Appearance
は物体の外見(見え方)に関する属税を定義するための重要なクラスです。
クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.Appearance クラス宣言 public class Appearance extends NodeComponent コンストラクター public Appearance()
三次元空間上の物体を定義する Shape3D
は、2つのオブジェクトを参照します。
まず最低限必要なのは Geometry
です。Geometry
は、物体の幾何学的な属性(座標や形状)を定義します。
もうひとつは Appearance
です。Appearance
は物体の外見(見え方)に関する属性を定義します。
Appearance
には、物体の外見についての属性を設定するための、数多くのメソッドがあります。
setMaterial()
)setPointAttributes()
)setLineAttributes()
)setPolygonAttributes()
)setColoringAttributes()
)setTransparencyAttributes()
)setRenderingAttributes()
)setTexture()
)setTextureAttributes()
)setTexCoordGeneration()
)setMaterial(Material)
メソッドはすでに説明しました。
以下では他のメソッドについて説明します。
点の属性 (javax.media.j3d.PointAttributes)
javax.media.j3d.PointAttributes
は、点の大きさ、点のアンチエリアス処理についての属性を定義します。
PointAttributes
は、setPoinAttributes()
メソッドで Appearance
に設定されます。
Appearance
のメソッド public final void setPointAttributes(PointAttributes pointAttributes) クラス宣言 public class PointAttributes extends NodeComponent コンストラクター public PointAttributes() public PointAttributes(float pointSize, // 点の大きさ(単位・ピクセル) boolean pointAntialiasing) // アンチエリアス処理をするかどうか
Java 3D での点の大きさは、デフォルト値では 1ピクセルです。PointAttributes
を使うと、点の大きさを変えることが可能です。点の大きさは float
値で設定します。単位はピクセルです。
アンチエリアス処理とは何でしょうか?
グラフィック表示の最小単位はピクセルです。ピクセルの大きさよりも小さい物体は表示できません。
例えば、画面上に描かれた線分を拡大すると次の図のようになります。
このような「ギザギザ」なものを、なめらかに見せる技法がアンチエリアスです。次の図を見てください。
ピクセルの大きさは変えられませんが、それぞれのピクセルに階調を持たせることで「ギザギザ」感を緩和しています。
アンチエリアス処理の有無は、デフォルトでは false
(処理しない) です。
PointAttributes
でアンチエリアスした点の描画サンプルを見てください。(Vine Linux Intel x86, JDK 1.2 pre-v2, Java 3D 1.1.1 pre-v1)
どの点も、大きさを 12.0f
にしています。
画面左側の 3つの点はアンチエリアス処理をしていません。画面右側の 3つの点はアンチエリアス処理してあります。
このサンプルのソースコードは次のようになっています。
AppearanceTest.java (一部)30 private BranchGroup createSceneGraph() { 31 BranchGroup root = new BranchGroup(); 32 33 Point3d[] vleft = new Point3d[3]; 34 35 vleft[0] = new Point3d(-0.9, 0.0, 0.0); 36 vleft[1] = new Point3d(-0.6, -0.4, 0.0); 37 vleft[2] = new Point3d(-0.2, 0.3, 0.0); 38 39 PointArray gleft = new PointArray(vleft.length, GeometryArray.COORDINATES); ┐ 40 gleft.setCoordinates(0, vleft); │ 41 │ 42 PointAttributes pleft = new PointAttributes();...(2) │ 43 pleft.setPointSize(12.0f);.......................(3) │ 44 ├(1) 45 Appearance aleft = new Appearance();.............(4) │ 46 aleft.setPointAttributes(pleft);.................(5) │ 47 │ 48 Shape3D sleft = new Shape3D(gleft, aleft);.......(6) │ 49 │ 50 root.addChild(sleft);............................(7) ┘ 51 52 Point3d[] vright = new Point3d[3]; 53 54 vright[0] = new Point3d(0.1, 0.0, 0.0); 55 vright[1] = new Point3d(0.3, -0.4, 0.0); 56 vright[2] = new Point3d(0.6, 0.1, 0.0); 57 58 PointArray gright = new PointArray(vright.length, GeometryArray.COORDINATES); ┐ 59 gright.setCoordinates(0, vright); │ 60 │ 61 PointAttributes pright = new PointAttributes(); │ 62 pright.setPointSize(12.0f); │ 63 pright.setPointAntialiasingEnable(true);............(9) │ 64 │ 65 Appearance aright = new Appearance(); ├(8) 66 aright.setPointAttributes(pright); │ 67 │ 68 Shape3D sright = new Shape3D(gright, aright); │ 69 │ 70 root.addChild(sright); ┘ 71 72 return root; 73 }
(1)で画面左の 3つの点を定義しています。
(2)で PointAttributes
を生成し、(3)で点の大きさを 12.0f
に設定しています。
(4)で Appearance
を生成し、(5)で setPointAttributes()
メソッドを使って PointAttributes
を設定しています。
(6)で PointArray, Appearance
をコンストラクターの引数に指定して Shape3D
を生成し、(7)で BranchGroup
に addChild()
しています。
(8)で画面右の 3つの点を定義しています。
左側の 3つの点と違い、(9)で setPointAntialiasingEnable()
メソッドを使って、アンチエリアス処理を有効にしています。
やっと、点がどこに描画されているのか分かるサンプルになりました。 これ以前のサンプルでは点の大きさが 1ピクセルしか無く、 何が描画されているのかよくわかりませんでした。
javax.media.j3d.LineAttributes
)
は、線分の太さ、実線、破線など線の種類、アンチエリアス処理の有無などを定義します。
LineAttributes
は、setLineAttributes()
メソッドで Appearance
に設定されます。
Appearance
のメソッド public final void setLineAttributes(LineAttributes lineAttributes) クラス継承 java.lang.Object | +--javax.media.j3d.SceneGraphObject | +--javax.media.j3d.NodeComponent | +--javax.media.j3d.LineAttributes クラス宣言 public class LineAttributes extends NodeComponent コンストラクター public LineAttributes() public LineAttributes(float lineWidth, // 線の太さ int linePattern, // 線の種類 boolean lineAntialiasing) // アンチエリアス処理をするかどうか 定数フィールド (一部) public static final int PATTERN_SOLID // 実線 public static final int PATTERN_DASH // 破線 public static final int PATTERN_DOT // 点線 public static final int PATTERN_DASH_DOT // 一点鎖線
線の太さは、PointAttributes
の点の大きさと同様に、デフォルト値は 1ピクセルです。コンストラクターの float lineWidth
または setLineWidth(float)
メソッドで設定します。
線の種類は実線、破線、点線、一点鎖線です。それぞれ LineAttributes.PATERN_xxxx
定数フィールドで指定します。
アンチエリアス処理は、PointAttributes
と同様に、デフォルト値では false
です。
このサンプルでは java.awt.TextField, java.awt.Choice, java.awt.Checkbox
を使って、各種設定値をいろいろ変化させてテストできるようにしてみました。
AppearanceTest.java1 // Java 3Dテスト用アプレット 2 // AppearanceTest.java 3 // Copyright (c) 1999 ENDO Yasuyuki 4 // mailto:yasuyuki@timedia.co.jp 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 15 public class AppearanceTest extends Applet { 16 Appearance ap = null; 17 18 public AppearanceTest() { 19 this.setLayout(new BorderLayout()); 20 21 Panel panel = new Panel(); 22 this.add(panel, BorderLayout.NORTH); 23 24 panel.add(new Label("Width")); 25 TextField tfield = new TextField("1.0", 8); 26 tfield.addActionListener(new ActionListener() { 27 public void actionPerformed(ActionEvent e) { 28 float width = 1.0f; 29 try { 30 width = Float.parseFloat(e.getActionCommand()); 31 System.out.println(width); 32 ap.getLineAttributes().setLineWidth(width);...(1) 33 } catch (NumberFormatException ex) { } 34 } 35 }); 36 panel.add(tfield); 37 38 panel.add(new Label("Pattern")); 39 Choice choice = new Choice(); 40 choice.add("PATTERN_SOLID"); 41 choice.add("PATTERN_DASH"); 42 choice.add("PATTERN_DOT"); 43 choice.add("PATTERN_DASH_DOT"); 44 choice.addItemListener(new ItemListener() { 45 public void itemStateChanged(ItemEvent e) { 46 String item = (String)e.getItem(); 47 System.out.println(item); 48 if (item.equals("PATTERN_SOLID")) { ┐ 49 ap.getLineAttributes().setLinePattern(LineAttributes.PATTERN_SOLID); │ 50 } else if (item.equals("PATTERN_DASH")) { │ 51 ap.getLineAttributes().setLinePattern(LineAttributes.PATTERN_DASH); │ 52 } else if (item.equals("PATTERN_DOT")) { ├(2) 53 ap.getLineAttributes().setLinePattern(LineAttributes.PATTERN_DOT); │ 54 } else if (item.equals("PATTERN_DASH_DOT")) { │ 55 ap.getLineAttributes().setLinePattern(LineAttributes.PATTERN_DASH_DOT); │ 56 } ┘ 57 } 58 }); 59 panel.add(choice); 60 61 Checkbox check = new Checkbox("Antialias", false); 62 check.addItemListener( new ItemListener() { 63 public void itemStateChanged(ItemEvent e) { 64 int state = e.getStateChange(); 65 if (state == ItemEvent.SELECTED) { ┐ 66 ap.getLineAttributes().setLineAntialiasingEnable(true); │ 67 } else if (state == ItemEvent.DESELECTED) { ├(3) 68 ap.getLineAttributes().setLineAntialiasingEnable(false); │ 69 } ┘ 70 } 71 }); 72 panel.add(check); 73 74 GraphicsConfiguration config = 75 SimpleUniverse.getPreferredConfiguration(); 76 Canvas3D canvas = new Canvas3D(config); 77 this.add(canvas, BorderLayout.CENTER); 78 79 SimpleUniverse universe = new SimpleUniverse(canvas); 80 universe.getViewingPlatform().setNominalViewingTransform(); 81 82 BranchGroup scene = createSceneGraph(); 83 84 universe.addBranchGraph(scene); 85 } 86 87 private BranchGroup createSceneGraph() { 88 BranchGroup root = new BranchGroup(); 89 90 Point3d[] vertices = new Point3d[6]; 91 92 vertices[0] = new Point3d(-0.7, -0.1, 0.0); 93 vertices[1] = new Point3d(-0.3, -0.7, 0.0); 94 vertices[2] = new Point3d(0.2, -0.7, 0.0); 95 vertices[3] = new Point3d(0.8, 0.0, 0.0); 96 vertices[4] = new Point3d(0.6, 0.4, 0.0); 97 vertices[5] = new Point3d(-0.6, 0.6, 0.0); 98 99 LineArray geometry = new LineArray(vertices.length, GeometryArray.COORDINATES); 100 geometry.setCoordinates(0, vertices); 101 102 Shape3D shape = new Shape3D(geometry); 103 104 ap = new Appearance(); 105 ap.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_READ);........(4) 106 107 LineAttributes lattr = new LineAttributes();....................(5) 108 lattr.setCapability(LineAttributes.ALLOW_WIDTH_WRITE); ┐ 109 lattr.setCapability(LineAttributes.ALLOW_PATTERN_WRITE); ├(6) 110 lattr.setCapability(LineAttributes.ALLOW_ANTIALIASING_WRITE); ┘ 111 lattr.setLineWidth(1.0f);.......................................(7) 112 lattr.setLinePattern(LineAttributes.PATTERN_SOLID);.............(8) 113 ap.setLineAttributes(lattr);....................................(9) 114 115 shape.setAppearance(ap); 116 117 root.addChild(shape); 118 119 return root; 120 }
(1)でTextField
に入力された線の太さを setLineWidth()
メソッドで LineAttributes
に設定しています。
(2)でChoice
で選ばれた線の種類を setLinePattern()
メソッドで LineAttributes
に設定しています。
(3)でCheckbox
で選択されたアンチエリアス処理の有無を setLineAntialiasingEnable()
メソッドで LineAttributes
に設定しています。
(4)で Appearance
の setCapability()
メソッドを使ってLineAttributes
の読み取り許可を設定しています。
(5)で LineAttributes
を生成し、(6)でcapability bit
を設定しています。
(7)で setLineWidth()
メソッドを使って線の太さを 1.0f
に設定し、(8)で setLinePattern()
メソッドを使って線の種類を LineAttributes.PATTERN_SOLID
(実線) に設定しています。
(9)で setLineAttributes()
メソッドを使って LineAttributes
を Appearance
に設定しています。
javax.media.j3d.PolygonAttributes
)javax.media.j3d.PolygonAttributes
は、ポリゴンの描画モードや、カリングの種類、ポリゴン・オフセットなどの属性を定義します。
PolygonAttributes
は setPolygonAttributes()
メソッドで Appearance
に設定されます。
Appearance
のメソッド public final void setPolygonAttributes(PolygonAttributes polygonAttributes) クラス宣言 public class PointAttributes extends NodeComponent コンストラクター public PolygonAttributes() public PolygonAttributes(int polygonMode, // ポリゴンの描画モード int cullFace, // カリングの種類 float polygonOffset) // ポリゴンオフセット public PolygonAttributes(int polygonMode, // ポリゴンの描画モード int cullFace, // カリングの種類 float polygonOffset, // ポリゴンオフセット boolean backFaceNormalFlip) // 法線ベクトルを裏面にも適用? 定数フィールド (一部) public static final int POLYGON_POINT // ポリゴンの頂点を描画 public static final int POLYGON_LINE // ポリゴンの辺を描画 public static final int POLYGON_FILL // ポリゴンの面を描画 public static final int CULL_NONE // カリングしない public static final int CULL_BACK // 裏面をカリング public static final int CULL_FRONT // 表面をカリング
ポリゴンの描画モードは、デフォルトでは POLYGON_FILL
(ポリゴンの面を描画) です。POLYGON_POINT
に設定するとポリゴンの頂点だけが描画され、POLYGON_LINE
に設定するとポリゴンの辺だけが描画されます。
カリングとは何でしょうか? cull は「摘む、摘み集める」という意味で、 花などを摘みとって集めるようなときや、 (質の悪い)家畜などをえり分けるときに使われる動詞です。 (研究社「新英和大辞典」より)
CGの分野では、「 不要な描画要素を、あらかじめ切り捨てて描画しない 」ことを言います。たとえば、閉じた多面体のポリゴンの各面の裏面は、 計算しても結局は描画されませんから、 最初から計算しない方が効率は良くなります。
Java 3Dでは、デフォルトでのカリングの設定は CULL_BACK
です。つまり、裏面は描画の対象から外されます。
CULL_FRONT
に設定すると表面が描画の対象から外されます。CULL_NONE
では表面、裏面ともに描画の対象となります。
裏面を描画するには、CULL_NONE
に設定するだけでは不十分です。boolean backFaceNormalFlip
を true
に設定する必要があります。この設定値は、法線ベクトルを裏面にも適用するもので、表面の(頂点の)法線ベクトルと逆方向のベクトルが裏面に適用されます。
ポリゴン・オフセットは特殊な描画処理をやり易くするために導入された設定値です。ポリゴン・オフセットは、次のような描画に有効のようです。
PolygonAttributes
を使ったサンプルは次のようなものです。
捻ったリボンのようなポリゴンを描画してあります。ポリゴンの裏面はデフォルトでは描画されません。
CULL_NONE
を選んで、チェックボックスで backFaceNormalFlip
を true
にすると表面、裏面が両方とも描画されます。
POLYGON_POINT, POLYGON_LINE, POLYGON_FILL
を選ぶと描画対象が頂点、辺、面に切り替わります。AppearanceTest.java1 // Java 3Dテスト用アプレット 2 // AppearanceTest.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.util.*; 11 import javax.media.j3d.*; 12 import javax.vecmath.*; 13 import com.sun.j3d.utils.applet.MainFrame; 14 import com.sun.j3d.utils.universe.SimpleUniverse; 15 import com.sun.j3d.utils.geometry.GeometryInfo; 16 import com.sun.j3d.utils.geometry.NormalGenerator; 17 18 public class AppearanceTest extends Applet { 19 Appearance ap = null; 20 21 public AppearanceTest() { 22 this.setLayout(new BorderLayout()); 23 24 Panel panel = new Panel(); 25 this.add(panel, BorderLayout.NORTH); 26 27 Checkbox checkbox = new Checkbox("NormalFlip", false); 28 checkbox.addItemListener(new ItemListener() { 29 public void itemStateChanged(ItemEvent e) { 30 System.out.println(e.getStateChange()); 31 switch (e.getStateChange()) { 32 case ItemEvent.SELECTED: 33 ap.getPolygonAttributes().setBackFaceNormalFlip(true);....(1) 34 break; 35 case ItemEvent.DESELECTED: 36 ap.getPolygonAttributes().setBackFaceNormalFlip(false);...(2) 37 break; 38 } 39 } 40 }); 41 panel.add(checkbox); 42 43 Choice cullChoice = new Choice(); 44 cullChoice.add("CULL_NONE"); 45 cullChoice.add("CULL_FRONT"); 46 cullChoice.add("CULL_BACK"); 47 cullChoice.select(2); 48 cullChoice.addItemListener(new ItemListener() { 49 public void itemStateChanged(ItemEvent e) { 50 String item = (String)e.getItem(); 51 if (item.equals("CULL_NONE")) { ┐ 52 ap.getPolygonAttributes().setCullFace(PolygonAttributes.CULL_NONE); │ 53 } else if (item.equals("CULL_FRONT")) { │ 54 ap.getPolygonAttributes().setCullFace(PolygonAttributes.CULL_FRONT);├(3) 55 } else if (item.equals("CULL_BACK")) { │ 56 ap.getPolygonAttributes().setCullFace(PolygonAttributes.CULL_BACK); │ 57 } ┘ 58 } 59 }); 60 panel.add(cullChoice); 61 62 Choice modeChoice = new Choice(); 63 modeChoice.add("POLYGON_FILL"); 64 modeChoice.add("POLYGON_LINE"); 65 modeChoice.add("POLYGON_POINT"); 66 modeChoice.addItemListener(new ItemListener() { 67 public void itemStateChanged(ItemEvent e) { 68 String item = (String)e.getItem(); 69 if (item.equals("POLYGON_FILL")) { 70 ap.getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_FILL); 71 } else if (item.equals("POLYGON_LINE")) { 72 ap.getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_LINE); 73 } else if (item.equals("POLYGON_POINT")) { 74 ap.getPolygonAttributes().setPolygonMode(PolygonAttributes.POLYGON_POINT); 75 } 76 } 77 }); 78 panel.add(modeChoice); 79 : : 94 GraphicsConfiguration config = 95 SimpleUniverse.getPreferredConfiguration(); 96 Canvas3D canvas = new Canvas3D(config); 97 98 this.add(canvas, BorderLayout.CENTER); 99 100 SimpleUniverse universe = new SimpleUniverse(canvas); 101 universe.getViewingPlatform().setNominalViewingTransform(); 102 103 BranchGroup scene = createSceneGraph(); 104 105 universe.addBranchGraph(scene); 106 } 107 108 private BranchGroup createSceneGraph() { 109 BranchGroup root = new BranchGroup(); 110 111 DirectionalLight light = new DirectionalLight(); 112 light.setInfluencingBounds(new BoundingSphere(new Point3d(), 100.0)); 113 root.addChild(light); 114 115 Point3d[] vertices = createPoints(); 116 int[] indices = createIndices(vertices.length); 117 118 GeometryInfo ginfo = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY); 119 ginfo.setCoordinates(vertices); 120 ginfo.setCoordinateIndices(indices); 121 NormalGenerator ngen = new NormalGenerator(); 122 ngen.generateNormals(ginfo); 123 124 Shape3D shape = new Shape3D(ginfo.getIndexedGeometryArray()); 125 126 ap = new Appearance(); 127 ap.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_READ); 128 129 PolygonAttributes pattr = new PolygonAttributes();..............(4) 130 pattr.setCapability(PolygonAttributes.ALLOW_CULL_FACE_WRITE); ┐ 131 pattr.setCapability(PolygonAttributes.ALLOW_MODE_WRITE); ├(5) 132 pattr.setCapability(PolygonAttributes.ALLOW_NORMAL_FLIP_WRITE); │ 133 pattr.setCapability(PolygonAttributes.ALLOW_OFFSET_WRITE); ┘ 134 ap.setPolygonAttributes(pattr);.................................(6) 135 136 Material mat = new Material(); 137 mat.setDiffuseColor(new Color3f(0.0f, 0.0f, 1.0f)); 138 ap.setMaterial(mat); 139 140 shape.setAppearance(ap); 141 142 root.addChild(shape); 143 144 return root; 145 } 146 147 public Point3d[] createPoints() { ...(7) : : 173 }
(1), (2)では、チェックボックスの選択状態に応じて setBackFaceNormalFlip()
メソッドを使って法線ベクトルを裏面にも適用するかどうかを設定しています。
(3)でChoice
の選択状態に応じて setCullMode()
メソッドを使ってポリゴンの描画モードを切替えています。
(4)で PolygonAttributes
を生成し、(5)で capabitily bit
を設定し、(6)で setPolygonAttributes()
メソッドを使って Appearance
に設定しています。
詳しい解説は省略しますが、(7)で捻ったリボンのようなポリゴンを定義しています。
javax.media.j3d.ColoringAttributes
)javax.media.j3d.ColoringAttributes
は、色の描画モードや物体の色を定義します。
ColoringAttributes
は setColoringAttributes()
メソッドで Appearance
に設定されます。
Appearance
のメソッド public final void setColoringAttributes(ColoringAttributes coloringAttributes) クラス宣言 public class ColoringAttributes extends NodeComponent コンストラクター public ColoringAttributes() public ColoringAttributes(Color3f color, // 設定する色 int shadeModel) // 色の描画モード public ColoringAttributes(float red, // 設定する色の赤要素 float green, // 設定する色の緑要素 float blue, // 設定する色の青要素 int shadeModel) // 色の描画モード 定数フィールド (一部) public static final int FASTEST // 可能な限り高速に描画 public static final int NICEST // 可能な限り高品質に描画 public static final int SHADE_FLAT // フラットシェーディング public static final int SHADE_GOURAUD // グーローシェーディング
GeometryArray
で設定する色は頂点ごとに指定しますが、ColoringAttributes
で設定する色は Shape3D
全体に適用されます。
すでに GeomeryArray
の setColor(), setColors()
で頂点に色が設定されていると、ColoringAttributes
で色を設定しても適用されません。
Appearance
に Material
が設定されているとき、ColoringAttributes
で色を設定すると ColoringAttributes
で設定した色が適用されます。
setColor()/setColors(), ColoringAttributes, Material
には次のような関係が成立ちます。
setColor()/setColors() >>優先>> ColoringAttributes >>優先>> Material
色の描画モードのデフォルトは SHADE_GOURAUD
(グーローシェーディング) です。頂点ごとに指定された色は、頂点間でスムースに補間されます。
SHADE_FLAT
(フラットシェーディング) に設定すると、ポリゴンの最後の頂点に適用した色がポリゴン全体に適用されます。他の頂点に設定した色は無視されます。
SHADE_NICEST, SHADE_FASTEST
は SHADE_GOURAUD
と同様に頂点間で色を補間しますが、可能な限り高品質に描画したり、可能な限り高速に描画したりする設定になります。ただしこの項目はハードウエア、ソフトウエア環境に依存しており、SHADE_GOURAUD
と異なる結果になるとは限りません。
サンプルプログラムの実行結果は次のようになります。
画面上の TriangleArray
には、頂点ごとの色指定はしてありません。
画面下の TriangleStripArray
には、頂点ごとに色を指定しました。
TextField
でR, G, Bを入力して、ColoroingAttributes
に色を設定したり、Choice
から色の描画モードを選択したりしてみてください。
このサンプルのソースコードはCD-ROMを参照してください。
AppearanceTest.java
色はR、G、Bそれぞれを数値入力するようにしました。この入力にはTextField
を使っても良いのですが、コードが繁雑になるのでjava.awt.Panel
を拡張したTuplePanel
クラスを書きました。
TuplePanel
はTuple3f, Tuple4f
のサブクラスならColor3f, Color4f
以外も使用できるようにしました。
TuplePanel
はTupleEvent
というイベントクラスを持ちます。ユーザー入力によって値が変化するとTupleEvent
が発生します。
TupleEvent.java1 // Java 3D Test Program 2 // TupleEnevt.java 3 // Copyright (c) 1999 ENDO Yasuyuki 4 // mailto:yasuyuki@javaopen.org 5 // http://www.javaopen.org/j3dbook/index.html 6 7 8 import java.util.EventObject; 9 import javax.vecmath.Tuple3f; 10 import javax.vecmath.Color3f; 11 import javax.vecmath.Point3f; 12 import javax.vecmath.Vector3f; 13 import javax.vecmath.Tuple4f; 14 import javax.vecmath.Color4f; 15 import javax.vecmath.Point4f; 16 import javax.vecmath.Vector4f; 17 import javax.vecmath.Quat4f; 18 19 public class TupleEvent extends EventObject { 20 protected Tuple3f tuple3f = null; 21 protected Tuple4f tuple4f = null; 22 public TupleEvent(Object source, Tuple3f tuple) { 23 super(source); 24 tuple3f = tuple; 25 } 26 public TupleEvent(Object source, Tuple4f tuple) { 27 super(source); 28 tuple4f = tuple; 29 } 30 public Tuple3f getTuple3f() { return tuple3f; } 31 public Color3f getColor3f() { return (Color3f)tuple3f; } 32 public Point3f getPoint3f() { return (Point3f)tuple3f; } 33 public Vector3f getVector3f() { return (Vector3f)tuple3f; } 34 public Tuple4f getTuple4f() { return tuple4f; } 35 public Color4f getColor4f() { return (Color4f)tuple4f; } 36 public Point4f getPoint4f() { return (Point4f)tuple4f; } 37 public Vector4f getVector4f() { return (Vector4f)tuple4f; } 38 public Quat4f getQuat4f() { return (Quat4f)tuple4f; } 39 }
TupleEvent
によるイベント通知を受けるためにはTupleEventListener
インターフェースを実装します。
TupleEventListener.java1 // Java 3D Test Program 2 // TupleEventListener.java 3 // Copyright (c) 1999 ENDO Yasuyuki 4 // mailto:yasuyuki@javaopen.org 5 // http://www.javaopen.org/j3dbook/index.html 6 7 public interface TupleEventListener { 8 void tupleStateChanged(TupleEvent e); 9 }
TupleEventListener
の実装クラスでは、tupleStateChanged()
メソッドの中で変化したTuple3f
またはTuple4f
を取得します。取得にはTulpeEvent
の次のメソッドが使用できます。
TupleEventのメソッド public Tuple3f getTuple3f() public Color3f getColor3f() public Point3f getPoint3f() public Vector3f getVector3f() public Tuple4f getTuple4f() public Color4f getColor4f() public Point4f getPoint4f() public Vector4f getVector4f() public Quat4f getQuat4f()
(1)でTuplePanel
を生成しています。(2)でaddTulpeEventListener()
メソッドを使って無名内部クラスをイベントリスナーとして登録しています。(3)がtupleStateChanged()
メソッドの宣言です。(4)では、TupleEvent#getColor3f()
メソッドで変化後のColor3f
を取得し、setColor()
メソッドでColoringAttributes
にセットしています。
24 TuplePanel tp = new TuplePanel(color);.................(1) 25 tp.addTupleEventListener( new TupleEventListener() {...(2) 26 public void tupleStateChanged(TupleEvent e) { ┐ 27 cattr.setColor(e.getColor3f());..............(4) ├(3) 28 } ┘ 29 }); 30 panel.add(tp);
(5)でChoice
で選択された項目を元に setShadeModel()
メソッドで色の描画モードとして設定しています。
32 Choice choice = new Choice(); 33 choice.add("FASTEST"); 34 choice.add("NICEST"); 35 choice.add("SHADE_FLAT"); 36 choice.add("SHADE_GOURAUD"); 37 choice.select(3); 38 choice.addItemListener(new ItemListener() { 39 public void itemStateChanged( ItemEvent e ){ 40 String item = (String)e.getItem(); 41 if (item.equals("FASTEST")) { ┐ 42 cattr.setShadeModel(ColoringAttributes.FASTEST); │ 43 } else if (item.equals("NICEST")) { │ 44 cattr.setShadeModel(ColoringAttributes.NICEST); │ 45 } else if (item.equals("SHADE_FLAT")) { ├(5) 46 cattr.setShadeModel(ColoringAttributes.SHADE_FLAT); │ 47 } else if (item.equals("SHADE_GOURAUD")) { │ 48 cattr.setShadeModel(ColoringAttributes.SHADE_GOURAUD); │ 49 } ┘ 50 } 51 }); 52 panel.add(choice);
(6)で ColoringAttributes
を生成し、(7)で capability bit
を設定し、(8)で setColoringAttributes()
メソッドを使って Appearance
に設定しています。
125 private Appearance createAppearance() { 126 Appearance ap = new Appearance(); 127 ap.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE); 128 129 cattr = new ColoringAttributes();..................................(6) 130 cattr.setCapability(ColoringAttributes.ALLOW_COLOR_READ); ┐ 131 cattr.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE); ├(7) 132 cattr.setCapability(ColoringAttributes.ALLOW_SHADE_MODEL_WRITE); ┘ 133 ap.setColoringAttributes(cattr);...................................(8) 134 135 return ap; 136 }
TuplePanel
のソースはCD-ROMを参照してください。イベント処理、イベント通知が大半なので解説は省略します。
TuplePanel.java
なお、TuplePanel
はJavaBeansとしての最低限の機能を持っていますが、次の点で汎用性に問題があります。
java.lang.Serializeable
を実装せず、シリアライズのためのメソッドも持たないあくまでも、テスト用として最低限の機能を実現するために書いたクラスです。
javax.media.j3d.TransparencyAttributes
)javax.media.j3d.TransparencyAttributes
は、物体の透明度や、その描画モードなどを定義します。
TransparencyAttributes
は、setTransparencyAttributes()
メソッドで Appearance
に設定されます。
Appearance
のメソッド public final void setTransparencyAttributes(TransparencyAttributes transparencyAttributes) クラス宣言 public class TransparencyAttributes extends NodeComponent コンストラクター public TransparencyAttributes() public TransparencyAttributes(int tMode, // 透明度の描画モード float tVal) // 透明度 定数フィールド (一部) public static final int FASTEST // 可能な限り高速に描画 public static final int NICEST // 可能な限り高品質に描画 public static final int BLENDED // アルファブレンドで描画 public static final int SCREEN_DOOR // 格子状に透過を描画 public static final intNONE // 透明度を描画しない
透明度の描画モードのデフォルト設定は NONE
(透明度を描画しない) です。BLENDED
に設定すると透明度が描画されます。FASTEST, NICEST
は BLENDED
と同じく透明度を描画しますが、FASTEST
では可能な限り高速に描画し、NICEST
では可能な限り高品質に描画する設定になります。ただしハードウエア、ソフトウエア環境によっては BLENDED
と結果が変わらないこともあり得ます。
透明度は 0.0f
が不透明で、1.0f
に近付くほど透明度は高くなります。デフォルト値は 0.0f
(不透明) です。
サンプルプログラムの実行結果を見てください。
TextField
に透明度を入力し、Choice
で透明度の描画モードを変化させてみてください。画面上の物体に透明度が適用されます。
このサンプルのソースは次の通りです。
AppearanceTest.java1 // Java 3Dテスト用アプレット 2 // AppearanceTest.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.Box; 15 import com.sun.j3d.utils.geometry.Cone; 16 import com.sun.j3d.utils.geometry.Sphere; 17 18 public class AppearanceTest extends Applet { 19 TransparencyAttributes tattr = null; 20 21 public AppearanceTest() { 22 Panel panel = new Panel(); 23 this.setLayout(new BorderLayout()); 24 this.add(panel, BorderLayout.NORTH); 25 26 panel.add(new Label("Transparency")); 27 TextField tfield = new TextField("0.0", 4); 28 tfield.addActionListener( new ActionListener() { 29 public void actionPerformed(ActionEvent e) { 30 float value = 0.0f; 31 try { 32 value = Float.parseFloat(e.getActionCommand()); 33 if (value > 1.0f) value = 1.0f; 34 if (value < 0.0f) value = 0.0f; 35 System.out.println("value=" + value); 36 tattr.setTransparency(value);.........(1) 37 } catch (NumberFormatException ex) { } 38 } 39 }); 40 panel.add(tfield); 41 42 Choice choice = new Choice(); 43 choice.add("BLENDED"); 44 choice.add("FASTEST"); 45 choice.add("NICEST"); 46 choice.add("NONE"); 47 choice.add("SCREEN_DOOR"); 48 choice.select(3); 49 choice.addItemListener( new ItemListener() { 50 public void itemStateChanged(ItemEvent e) { 51 String item = (String)e.getItem(); 52 if (item.equals("BLENDED")) { ┐ 53 tattr.setTransparencyMode(TransparencyAttributes.BLENDED); │ 54 } else if (item.equals("FASTEST")) { │ 55 tattr.setTransparencyMode(TransparencyAttributes.FASTEST); │ 56 } else if (item.equals("NICEST")) { │ 57 tattr.setTransparencyMode(TransparencyAttributes.NICEST); ├(2) 58 } else if (item.equals("NONE")) { │ 59 tattr.setTransparencyMode(TransparencyAttributes.NONE); │ 60 } else if (item.equals("SCREEN_DOOR")) { │ 61 tattr.setTransparencyMode(TransparencyAttributes.SCREEN_DOOR); │ 62 } ┘ 63 } 64 }); 65 panel.add(choice); 66 67 GraphicsConfiguration config = 68 SimpleUniverse.getPreferredConfiguration(); 69 70 Canvas3D canvas = new Canvas3D(config); 71 this.add(canvas, BorderLayout.CENTER); 72 73 SimpleUniverse universe = new SimpleUniverse(canvas); 74 universe.getViewingPlatform().setNominalViewingTransform(); 75 76 universe.addBranchGraph(createSceneGraph()); 77 } 78 79 public BranchGroup createSceneGraph() { 80 BranchGroup root = new BranchGroup(); 81 82 Light light1 = createLight( new Color3f(0.7f, 0.7f, 0.7f), 83 new Vector3f(0.5f, -0.5f, -0.7f) ); 84 root.addChild(light1); 85 86 Light light2 = createLight( new Color3f(0.3f, 0.3f, 0.3f), 87 new Vector3f(-0.5f, -0.5f, -0.7f) ); 88 root.addChild(light2); 89 90 Transform3D t3d = new Transform3D(); 91 t3d.rotX(Math.PI / 8.0); 92 Transform3D roty = new Transform3D(); 93 roty.rotY(Math.PI / 4.0); 94 t3d.mul(roty); 95 96 TransformGroup trans = new TransformGroup(t3d); 97 root.addChild(trans); 98 99 Appearance yapp = createAppearance( new Color3f(1.0f, 1.0f, 0.0f) ); 100 Appearance rapp = createAppearance( new Color3f(1.0f, 0.0f, 0.0f) ); 101 Appearance bapp = createAppearance( new Color3f(0.0f, 0.0f, 1.0f) ); 102 103 Transform3D bt3d = new Transform3D(); 104 bt3d.set(new Vector3d(-0.22, -0.02, 0.22)); 105 TransformGroup btrans = new TransformGroup(bt3d); 106 btrans.addChild(new Box( 0.16f, 0.16f, 0.16f, yapp )); 107 trans.addChild(btrans); 108 109 Transform3D ct3d = new Transform3D(); 110 ct3d.set( new Vector3d(-0.2, 0.0, -0.2) ); 111 TransformGroup ctrans = new TransformGroup(ct3d); 112 ctrans.addChild( new Cone( 0.2f, 0.4f, Cone.BODY | Cone.CAP, rapp ) ); 113 trans.addChild(ctrans); 114 115 Transform3D st3d = new Transform3D(); 116 st3d.set( new Vector3d(0.2, 0.0, 0.2) ); 117 TransformGroup strans = new TransformGroup(st3d); 118 strans.addChild( new Sphere(0.2f, bapp) ); 119 trans.addChild(strans); 120 121 return root; 122 } 123 124 private Light createLight(Color3f color, Vector3f vec) { 125 DirectionalLight light = new DirectionalLight( color, vec ); 126 light.setInfluencingBounds( new BoundingSphere( new Point3d(), 100.0 ) ); 127 128 return light; 129 } 130 131 private Appearance createAppearance(Color3f color) { 132 Appearance ap = new Appearance(); 133 ap.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE); 134 135 Material mat = new Material(); 136 mat.setDiffuseColor(color); 137 //mat.setSpecularColor(new Color3f(0.0f, 0.0f, 0.0f)); 138 //mat.setShininess(127.0f); 139 ap.setMaterial(mat); 140 141 if (tattr == null) { 142 tattr = new TransparencyAttributes();...........................(3) 143 tattr.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE); ┬(4) 144 tattr.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE); ┘ 145 } 146 ap.setTransparencyAttributes(tattr);..............................(5) 147 148 return ap; 149 }
(3)でTextField
に入力された値を元に setTransparency()
メソッドを使って透明度を設定しています。
Choice で選択された項目を元に setTransparencyMode()
メソッドを使って透明度の描画モードを設定しています。
(5)で TransparencyAttributes
を生成し、(6)で capabitily bit
を設定し、(7)で setTransparencyAttributes()
メソッドを使って Appearance
に設定しています。
現実世界とは違い、Java 3Dでの透明度の表現は色の混合によって実現されています。
複数の物体に前後関係があるとき、色の混合がうまく行かない場合があります。うまく行かない場合は、奥にある物体を先に描画しなければならないことがあります。
javax.media.j3d.RenderingAttributes
)javax.media.j3d.RenderingAttributes
は、デプスバッファーの有効/無効、デプスバッファーへの書き込みの有効/無効、アルファテストのテスト値やテスト方法などを定義します。
RenderingAttributes
は setRenderingAttributes()
メソッドで Appearance
に設定されます。
Appearance
のメソッド public final void setRenderingAttributes(RenderingAttributes renderingAttributes) クラス宣言 public class RenderingAttributes extends NodeComponent コンストラクター public RenderingAttributes() public RenderingAttributes(boolean depthBufferEnable, // デプスバッファーの有効/無効 boolean depthBufferWriteEnable, // デプスバッファーへの書き込みの有効/無効 float alphaTestValue, // アルファテストのための値 int alphaTestFunction) // アルファテストの方法 定数フィールド (一部) public static final int ALWAYS // 常に描画する public static final int NEVER // 常に描画しない public static final int EQUAL // テスト値と等しいとき描画 == alphaTestValue public static final int NOT_EQUAL // テスト値と等しくないとき描画 != alphaTestValue public static final int LESS // テスト値より小なら描画 < alphaTestValue public static final int LESS_OR_EQUAL // テスト値以下なら描画 <= alphaTestValue public static final int GREATER // テスト値より大なら描画 > alphaTestValue public static final int GREATER_OR_EQUAL // テスト値以上なら描画 >= alphaTestValue
デプスバッファーとは何でしょうか?
現実世界で我々がものを見るとき、奥にある物体は手前にある物体に隠れて見えなくなります。
CG でこれを実現する方法はいくつかあります。たとえば、最も奥にあるポリゴンを最初に描画し、最も手前にあるポリゴンを最後に描画すればとりあえずは実現できます。
ただしこの方法では、ポリゴンが交差した場合や、物体が移動/回転/変形したり、視点が移動/回転する場合などに不都合が生じることがあります。
別の方法として、デプスバッファーを使う方法があります。デプスバッファーを使う場合、物体を描画する順番と無関係に実現することができます。
デプスバッファーは、スクリーンの各ピクセルごとに、「視点から物体までの距離」(深度値)と色を保持しています。
デプスバッファーを使った描画では、次のようなことが行われます。
RenderingAttributes
では、このデプスバッファーによる描画を有効にしたり、無効にしたりすることができます。デフォルト値では有効です。
デプスバッファーを無効にしたい場合とはどんな場合でしょうか?
透明の物体と不透明の物体があり、その前後関係が変化するようなとき、デプスバッファーを使うとうまく描画できないときがあるようです。このような場合には奥にあるポリゴンを先に描画し、手前にあるポリゴンを後から描画する必要が生じることがあります。
このような場合はデプスバッファーを無効にし、javax.media.j3d.OrderedGroup
などを使って奥から順番に物体を描画してやる、といった方法が考えられます。
アルファテストとは何でしょうか?
ここで言う「アルファ」とは、物体の「不透明の度合」です。不透明の度合の範囲は 0.0f〜1.0f
です。1.0f
では完全に不透明、0.0f
では完全に透明です。
javax.media.Alpha
というクラスがあります。物体の「不透明の度合」に「アルファ」という用語を使用するのは混乱の元ではないかと思います。このことを意識したのか、物体の「透明度」に関しては Transparency という用語が使われています。RenderingAttributes
の alhpaTest
ではアルファという用語が使われていますが、このアルファは javax.media.Alpha
とは関係ありません。アルファテストは物体のピクセルごとに行われます。
0.0〜1.0
です。テスト方法にには次のようなものがあります。
ALWAYS | 常に描画する |
---|---|
NEVER | 常に描画しない |
EQUAL | テスト値と等しいとき描画 |
NOT_EQUAL | テスト値と等しくないとき描画 |
LESS | テスト値より小なら描画 |
LESS_OR_EQUAL | テスト値以下なら描画 |
GREATER | テスト値より大なら描画 |
GREATER_OR_EQUAL | テスト値以上なら描画 |
ALLWAYS, NEVER
では、ピクセルは常に描画されるか、全く描画されないかになります。
EQUAL, NOT_EQUAL
では、テスト値と等しいピクセルだけが描画されるか、またはそれだけ描画されないかになります。一度に描けるのは一つだけになりますが、等高線のようなものを描くことも可能です。
LESS, LESS_OR_EQUAL, GRATER, GLEATER_OR EQUAL
では、大小比較した結果によってピクセルを描画するかしないかを判定できます。
アルファテストを利用すると、マスク合成のような効果を得ることもできます。
サンプルプログラムの実行例を見てください。
このサンプルはフリーの地図データを元にモデリングしました。
タイトル:標高データ 立山カルデラ周辺
著作権者:NABE さん
http://www.vector.co.jp/soft/data/home/se021130.htmlread.me より:
転載等について ・このアーカイブファイルに含まれるデータの著作権は著者に属するものとします。 ・このデータを使用したことによる損害等には著者は一切の責任を負いません。 ・データの転載や再配布については、自由に行ってもかまいませんが、以下の3点を 明記して下さい。 1. 転載・再配布に金銭の授受を伴わないこと(ただし手数料を除く) 2. (筆者の読みとり能力から)このデータには100%の信頼性が伴わないこと 3. このデータは、国土地理院発行の25,000分の1地形図”立山”(H3.7.1) の一部を、100m毎に、その等高線から標高を読んでいったものであること
このサンプルでは、javax.vecmath.Color4f
を使って各頂点に不透明度を設定しています。
最も標高が低い頂点の不透明度を 0.0f
に、最も標高が高い頂点の不透明度を 1.0f
にしてあります。
この実行例では、アルファテストのテスト方法を GREATER
(テスト値より大なら描画) にし、テスト値を 0.3f
にしてあります。これで、不透明度が 0.3f
以下のピクセルは描画されなくなります。
テスト方法をいろいろ変えてみてください。たとえば EQUAL
を選ぶと等高線のようなものが描けます。
AppearanceTest.java(一部)1 // Java 3Dテスト用アプレット 2 // AppearanceTest.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.io.*; 11 import java.net.*; 12 import java.util.*; 13 import javax.media.j3d.*; 14 import javax.vecmath.*; 15 import com.sun.j3d.utils.applet.MainFrame; 16 import com.sun.j3d.utils.universe.SimpleUniverse; 17 import com.sun.j3d.utils.geometry.Box; 18 import com.sun.j3d.utils.geometry.Cone; 19 import com.sun.j3d.utils.geometry.Sphere; 20 import com.sun.j3d.utils.behaviors.mouse.*; 21 22 public class AppearanceTest extends Applet { 23 boolean isStandalone = false; 24 25 SimpleUniverse universe = null; 26 BranchGroup scene = null; 27 28 TransparencyAttributes tattr = null; 29 RenderingAttributes rattr = null; 30 31 public AppearanceTest() { 32 this(false); 33 } 34 35 public AppearanceTest(boolean isStandalone) { 36 this.isStandalone = isStandalone; 37 38 this.setLayout(new BorderLayout()); : : 127 Choice achoice = new Choice(); 128 achoice.add("ALWAYS"); 129 achoice.add("NEVER"); 130 achoice.add("EQUAL"); 131 achoice.add("NOT_EQUAL"); 132 achoice.add("LESS"); 133 achoice.add("LESS_OR_EQUAL"); 134 achoice.add("GREATER"); 135 achoice.add("GREATER_OR_EQUAL"); 136 achoice.addItemListener(new ItemListener() { 137 public void itemStateChanged(ItemEvent e) { 138 String item = (String)e.getItem(); 139 if (item.equals("ALWAYS")) { ┐ 140 rattr.setAlphaTestFunction(RenderingAttributes.ALWAYS); │ 141 } else if (item.equals("NEVER")) { │ 142 rattr.setAlphaTestFunction(RenderingAttributes.NEVER); │ 143 } else if (item.equals("EQUAL")) { │ 144 rattr.setAlphaTestFunction(RenderingAttributes.EQUAL); │ 145 } else if (item.equals("NOT_EQUAL")) { │ 146 rattr.setAlphaTestFunction(RenderingAttributes.NOT_EQUAL); │ 147 } else if (item.equals("LESS")) { ├(1) 148 rattr.setAlphaTestFunction(RenderingAttributes.LESS); │ 149 } else if (item.equals("LESS_OR_EQUAL")) { │ 150 rattr.setAlphaTestFunction(RenderingAttributes.LESS_OR_EQUAL); │ 151 } else if (item.equals("GREATER")) { │ 152 rattr.setAlphaTestFunction(RenderingAttributes.GREATER); │ 153 } else if (item.equals("GREATER_OR_EQUAL")) { │ 154 rattr.setAlphaTestFunction(RenderingAttributes.GREATER_OR_EQUAL); │ 155 } ┘ 156 } 157 }); 158 downpanel.add(achoice); 159 160 downpanel.add( new Label("AlphaTestValue") ); 161 TextField afield = new TextField("0.0", 4); 162 afield.addActionListener(new ActionListener() { 163 public void actionPerformed(ActionEvent e) { 164 float value = 0.0f; 165 try { 166 value = Float.parseFloat(e.getActionCommand()); 167 System.out.println("value=" + value); 168 rattr.setAlphaTestValue(value);....................(2) 169 } catch (NumberFormatException ex) {} 170 } 171 }); 172 downpanel.add(afield); 173 } 174 175 public void init() { 176 GraphicsConfiguration config = 177 SimpleUniverse.getPreferredConfiguration(); 178 179 Canvas3D canvas = new Canvas3D(config); 180 this.add(canvas, BorderLayout.CENTER); 181 182 universe = new SimpleUniverse(canvas); 183 universe.getViewingPlatform().setNominalViewingTransform(); 184 //universe.getViewer().getView().setDepthBufferFreezeTransparent(false); 185 186 scene = createSceneGraph(); 187 188 universe.addBranchGraph(scene); 189 } 190 191 public BranchGroup createSceneGraph() { 192 BranchGroup root = new BranchGroup(); 193 root.setCapability(BranchGroup.ALLOW_DETACH); 194 195 GeometryArray geom = null; 196 try { 197 geom = createGeometry(); 198 } catch (IOException ex) { 199 ex.printStackTrace(); 200 } 201 202 Appearance app = createAppearance(); 203 204 Shape3D mesh = new Shape3D(geom, app); 205 206 root.addChild(mesh); 207 208 return root; 209 } 210 211 private GeometryArray createGeometry() throws IOException { ...(3) 212 BufferedReader in = null; 213 214 if (isStandalone) { 215 in = new BufferedReader( new FileReader("tatecal.txt") ); 216 } else { 217 URL url = new URL(getCodeBase() + "tatecal.txt"); 218 URLConnection conn = url.openConnection(); 219 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); 220 } 221 final float XWEST = -0.8f; 222 float x = XWEST; 223 float y = 0.64f; 224 225 float dx = 2.0f * -x / 100.0f; 226 float dy = 2.0f * y / 80.0f; 227 float zmax = 0.0f; 228 float zmin = 0.0f; 229 String line = null; 230 Point3f[] vertices = new Point3f[101*81]; 231 int i = 0; 232 int l = 0; 233 while ( (line = in.readLine()) != null ) { 234 StringTokenizer st = new StringTokenizer(line, " ,", false); 235 String height = null; 236 while (st.hasMoreTokens()) { 237 float z = 0.0f; 238 height = st.nextToken(); 239 try { 240 z = (Float.parseFloat(height) - 1500.0f) / 3125.0f; 241 if (z > zmax) zmax = z; 242 if (z < zmin) zmin = z; 243 vertices[i] = new Point3f(x, y, z); 244 i++; 245 } catch (NumberFormatException ex) {} 246 x += dx; 247 } 248 x = XWEST; 249 y -= dy; 250 l++; 251 } 252 253 float range = zmax - zmin; 254 Color4f[] colors = new Color4f[101*81]; 255 for (i=0; i<(101*81); i++) colors[i] = createColor(vertices[i].z, zmin, range); 256 257 int[] indices = new int[100*79*4]; 258 int n = 0; 259 for (i=0; i<79; i++) { 260 for (int j=0; j<100; j++) { 261 indices[n++] = i * 101 + j; 262 indices[n++] = (i + 1) * 101 + j; 263 indices[n++] = (i + 1) * 101 + j + 1; 264 indices[n++] = i * 101 + j + 1; 265 } 266 } 267 268 IndexedQuadArray geometry = 269 new IndexedQuadArray( vertices.length, 270 GeometryArray.COORDINATES | 271 GeometryArray.COLOR_4, 272 indices.length ); 273 geometry.setCoordinates(0, vertices); 274 geometry.setCoordinateIndices(0, indices); 275 geometry.setColors(0, colors); 276 geometry.setColorIndices(0, indices); 277 278 return geometry; 279 } 280 281 private Color4f createColor(float z, float zmin, float range) { ...(4) 282 final Color4f green = new Color4f(0.0f, 1.0f, 0.0f, 0.0f); 283 final Color4f brown = new Color4f(0.5f, 0.3f, 0.1f, 0.0f); 284 final Color4f white = new Color4f(1.0f, 1.0f, 1.0f, 0.0f); 285 Color4f color = new Color4f(); 286 float a = (z - zmin) / range; 287 if (a < 0.5f) color.interpolate(green, brown, a * 2.0f); 288 else color.interpolate(brown, white, (a - 0.5f) * 2.0f); 289 color.w = a; 290 291 return color; 292 } 293 294 private Appearance createAppearance() { 295 Appearance ap = new Appearance(); 296 ap.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE); 297 298 tattr = new TransparencyAttributes(); 299 tattr.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE); 300 tattr.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE); 301 302 ap.setTransparencyAttributes(tattr); 303 304 rattr = new RenderingAttributes();........................................(5) 305 rattr.setCapability(RenderingAttributes.ALLOW_ALPHA_TEST_VALUE_WRITE); ┐ 306 rattr.setCapability(RenderingAttributes.ALLOW_ALPHA_TEST_FUNCTION_WRITE); ├(6) 307 rattr.setCapability(RenderingAttributes.ALLOW_DEPTH_ENABLE_READ); ┘ 308 //rattr.setDepthBufferWriteEnable(false); 309 //rattr.setDepthBufferEnable(false); 310 311 ap.setRenderingAttributes(rattr);.........................................(7) 312 313 return ap; 314 }
(1)でChoice
での選択項目に応じて、setAlphaTestFunction()
メソッドでアルファテストのテスト方法を設定しています。
(2)でTextField
に入力されたテスト値を setAlphaTestValue()
メソッドで設定しています。
(3)でファイルから数値データを読み取り、IndexedQuadArray を生成し、頂点データ、色と不透明度を設定しています。
(4)で標高に応じた色と不透明度を計算しています。最も標高が低い頂点の不透明度は 0.0f
、最も標高が高い頂点の不透明度は 1.0f
になるように計算しています。色は、最も標高が低い頂点は緑、中間では茶色、最も標高が高い頂点は白になるように、Color4f
の interpolate()
メソッドを使って補間しています。
(5)で RenderingAttributes
を生成し、(6)で capability bit
を設定し、(7)で setRenderingAttributes()
メソッドを使って Appearence
に設定しています。