• 検索結果がありません。

3D 描画 Step1-1 まず O 原子となる球を 1 つ描画する <WaterPanel.java の作成 > 1.Chemical プロジェクトをインポート 共有フォルダから Chemical.zip をコピーして workspace 内にはりつけ パッケージ エクスプローラで右クリック イン

N/A
N/A
Protected

Academic year: 2021

シェア "3D 描画 Step1-1 まず O 原子となる球を 1 つ描画する <WaterPanel.java の作成 > 1.Chemical プロジェクトをインポート 共有フォルダから Chemical.zip をコピーして workspace 内にはりつけ パッケージ エクスプローラで右クリック イン"

Copied!
11
0
0

読み込み中.... (全文を見る)

全文

(1)

-1-

GUI プログラミング第 4 回演習 3DChemical

~ OpenGL(JOGL)による3D 描画:水の化学式モデルを書いてみる ~ ↑実際は背景は黒くする <Eclipse を起動する> 1.eclipse.zip を D:ドライブにコピーし、右クリック→ここに解凍 2.workspace を S:ドライブから D:ドライブにコピー 3.eclipse.exe を起動 4.workspace を D:workspace に設定 <ステップ> ステップ1-1 O 原子となる球を1つ描画 ステップ1-2 水の化学式モデルを描画 ステップ2 マウスで回転できるようにする ステップ3 描画した立体の 2D 上の表示位置を取得し、元素名を 2D 描画する 104.45°

(2)

-2-

3D 描画 Step1-1】

まず、O 原子となる球を1つ描画する <WaterPanel.java の作成> 1.Chemical プロジェクトをインポート ・共有フォルダからChemical.zip をコピーして workspace 内にはりつけ ・パッケージ・エクスプローラで右クリック→インポート→一般 →既存のプロジェクトをワークスペースへ→「次へ」 ・アーカイブ・ファイルの参照からD:workspace¥Chemical.zip を選択して開く ・「完了」ボタンを押下 2.パッケージを作成 src フォルダを選択→右クリック→新規→パッケージ パッケージ名water 3.WaterPanel クラスを作成

…GLJPanel を継承(extends)、GLEventListener, MouseListener, MouseMotionListener を実装 (implements)したクラス water パッケージを選択→右クリック→新規→クラス ・クラス名WaterPanel ・スーパークラスの参照をクリック→「GLJPanel」とうつと、javax.media.opengl の GLJPanel が出てくるので、それを選択してOK ・インターフェースの追加をクリック →「GLEventListener」で出てくるクラスを選択して「追加」 →「MouseListener」で出てくるクラスを選択して「追加」 →「MouseMotionListener」で出てくるクラスを選択して「追加」・「OK」 ・「完了」ボタンを押下 4.ソースを編集(次ページ以降を参照)

変数→コンストラクタ→init メソッド→reshape メソッド→display メソッドの順に記述すると理解 しやすい。

(3)

WaterPanel.java -3- package chemical.water; 1 2 import java.awt.event.MouseEvent; 3 import java.awt.event.MouseListener; 4 import java.awt.event.MouseMotionListener; 5 6 import javax.media.opengl.GL; 7 import javax.media.opengl.GLAutoDrawable; 8 import javax.media.opengl.GLEventListener; 9 import javax.media.opengl.GLJPanel; 10 import javax.media.opengl.glu.GLU; 11 12 import com.sun.opengl.util.GLUT; 13 14

public class WaterPanel extends GLJPanel implements GLEventListener,

15 MouseListener, MouseMotionListener { 16 17 private GL gl; // OpenGL の関数群をもつオブジェクトその1 18

private GLU glu; // OpenGL の関数群をもつオブジェクトその2

19

private GLUT glut; // OpenGL の関数群をもつオブジェクトその3

20

private int div = 20; // 球、円柱の分割数

21 22

// 軸と O-H のなす角(※水の O-H がなす角は 104.45 度)

23

private float degree = (180-104.45f)/2.0f;

24 25 /* 光 ---*/ 26 // 光の位置 {x 座標, y 座標, z 座標, 光源までの距離(0 は無限円)} 27

private float[] lPosition = { -10.0f, 10.0f, 10.0f, 0.0f };

28

// 光の色 {R, G, B, アルファ(透明度)} ※数値は 0 から 1 まで

29

private float[] lSpecular = { 0.8f, 0.8f, 0.8f, 1.0f }; // 鏡面

30

private float[] lDiffuse = { 0.8f, 0.8f, 0.8f, 1.0f }; // 拡散

31

private float[] lAmbient = { 0.4f, 0.4f, 0.4f, 1.0f }; // 環境

32 33 /* 物体の反射率 ---*/ 34 // {R, G, B, アルファ(透明度)} ※数値は 0 から 1 まで 35

private float[] mSpecular = { 0.3f, 0.3f, 0.3f, 1.0f }; // 鏡面

36

private float[] mDiffuse = { 0.2f, 0.2f, 0.2f, 1.0f }; // 拡散

37

// 鏡面係数:きらめきの度合い(0~128)

38

private float mShininess = 10.0f;

39 40 /* 色の定義 ---*/ 41 // {R, G, B, アルファ(透明度)} ※数値は 0 から 1 まで 42

private float[] blue = { 0.0f, 0.0f, 1.0f, 1.0f }; // 青

43

private float[] red = { 1.0f, 0.0f, 0.0f, 1.0f }; // 赤

44

private float[] green = {0.0f, 1.0f, 0.5f, 1.0f }; // 緑

45 46 47 /** 48 * コンストラクタ 49 */ 50 public WaterPanel() { 51 // MouseEvent を受け取れるようにする 52 addMouseListener(this); 53 // MouseMotionEvent を受け取れるようにする 54 addMouseMotionListener(this); 55 // 3D 描画できるようにリスナ登録 56 addGLEventListener(this); 57 } 58 59 60 /* 3D 描画 ************************************************************/ 61 62 /** 63 * GLEventListener のメソッド:3D 描画メソッド 64

(4)

WaterPanel.java -4- */ 65 @Override 66

public void display(GLAutoDrawable drawable) {

67 // 背景色で塗りつぶし 68 gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); 69 // 現時点のマトリクス(Modelview 行列)を保存 ※必ず glPopMatrix()と対で使用する 70 /* glPushMatrix と glPopMatrix()は、座標を回転したり平行移動したり 71 * したものを、する前の状態を覚えておくために使う。 72 * これを使わないと、回転などがどんどん重なっていってしまう。 */ 73 gl.glPushMatrix(); 74 // z軸上 15 の位置から原点を見る,上方向は y 軸 75

// glulookat(視点の位置 x,y,z, 視点から見る座標 x,y,z, 上方向ベクトル x,y,z)

76 glu.gluLookAt(0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); 77 // y 軸正方向に少しずらす(平行移動) 78 gl.glTranslatef(0.0f, 0.4f, 0.0f); 79 80 /* O 原子を原点に描画 ---*/ 81 // 色指定 ※環境光の反射率とは、つまり物体の色になる 82

gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, red, 0);

83

// 塗りつぶしの球を描画

84

// glutSolidSphere(半径, Z 軸まわりの分割数, Z 軸に沿った分割数)

85

glut.glutSolidSphere(0.3, div, div);

86 87 // glPushMatrix()を呼ぶ前の行列の状態に戻す 88 gl.glPopMatrix(); 89 } 90 91 /** 92 * GLEventListener のメソッド:表示の切り替えが発生した場合に呼ばれる 93 * 今回は特に記述することはない 94 */ 95 @Override 96

public void displayChanged(GLAutoDrawable drawable, boolean modeChanged,

97 boolean deviceChanged) { 98 } 99 100 /** 101 * GLEventListener のメソッド:初期化時に呼ばれる 102 */ 103 @Override 104

public void init(GLAutoDrawable drawable) {

105

// OpenGL の関数群をもつオブジェクトを取得

106

gl = drawable.getGL();

107

glu = new GLU();

108

glut = new GLUT();

109 // 背景色を黒に設定 110 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 111 // 影に隠れて見えないものは表示しない 112 gl.glEnable(GL.GL_DEPTH_TEST); 113 // 光を有効にする 114 gl.glEnable(GL.GL_LIGHTING); 115 gl.glEnable(GL.GL_LIGHT0); 116 // 光の反射の法線ベクトルを正規化 117 gl.glEnable(GL.GL_NORMALIZE); 118 // 光の位置を設定 119 /* 4 番目の数字はオフセット。 120 * JOGL は c++のソースを JAVA に自動変換している。 121 * c++では配列はポインタなので、オフセットの概念がある 122 * JAVA にポインタはないので引数が増やされているのだが、 123 * オフセットの数字は 0 でよい。 */ 124

gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lPosition, 0);

125

// 光の色を設定

126

gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, lSpecular, 0); // 鏡面

127

gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, lDiffuse, 0); // 拡散

(5)

WaterPanel.java

-5-

gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, lAmbient, 0); // 環境

129

// 物体の反射率を設定

130

gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mSpecular, 0); // 鏡面

131

gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mDiffuse, 0); // 拡散

132

gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, mShininess); // 鏡面係数

133 } 134 135 /** 136 * GLEventListener のメソッド:表示領域が変更されたときに呼ばれる 137 */ 138 @Override 139

public void reshape(GLAutoDrawable drawable, int x, int y, int width,

140

int height) {

141

// ビューポート(描画領域)を設定

142

gl.glViewport(0, 0, width, height);

143 // マトリクスとして Projection 行列を対象にする 144 gl.glMatrixMode(GL.GL_PROJECTION); 145 // マトリクスを単位行列で初期化 146 gl.glLoadIdentity(); 147 // 視点の設定(参考資料を参照) 148

// gluPerspactive(視野角, 縦横比, near, far);

149 glu.gluPerspective(10.0, (double)width/(double)height, 1.0, 100.0); 150 // マトリクスとして ModelView 行列を対象にする 151 gl.glMatrixMode(GL.GL_MODELVIEW); 152 } 153 154 /* MouseListener のメソッド **************************************************/ 155 156 @Override 157

public void mouseClicked(MouseEvent e) {

158

// TODO Auto-generated method stub

159 160 } 161 162 @Override 163

public void mouseEntered(MouseEvent e) {

164

// TODO Auto-generated method stub

165 166 } 167 168 @Override 169

public void mouseExited(MouseEvent e) {

170

// TODO Auto-generated method stub

171 172 } 173 174 @Override 175

public void mousePressed(MouseEvent e) {

176

// TODO Auto-generated method stub

177 } 178 179 @Override 180

public void mouseReleased(MouseEvent e) {

181

// TODO Auto-generated method stub

182 } 183 184 /* MouseMotionListener のメソッド *************************************************/ 185 186 @Override 187

public void mouseDragged(MouseEvent e) {

188

// TODO Auto-generated method stub

189 190

}

191 192

(6)

WaterPanel.java

-6-

@Override

193

public void mouseMoved(MouseEvent e) {

194

// TODO Auto-generated method stub

195 196 } 197 198 } 199 <WaterFrame.java の作成> 1.フレームを作成 chemical パッケージ選択→右クリック→新規→その他を選択 GUI Forms→Swing→JFrame を選んで「次へ」

Class Name は WaterFrame として「完了」 2.Jigloo のメッセージが出てきたら「OK」 3.Look&Feel(プログラムの見た目)を設定 フレームを選択→右クリック→Set Look&Feel→Windows を選択 4.レイアウトを設定 フレームを選択→右クリック→Set Layout→BorderLayout を選択 5.フレームのサイズを大きめにする ソースの方をみて、initGUI()の中の下の方にあるサイズ指定部分を編集 setSize(400,300); → setSize(400,400); 6.フレームのプレビューに戻り、パネルをSouth に追加 上部の「Containers」右から 5 番目の「JPanel」を選び、フレームに貼り付ける 名前はsouthPanel、Constraints の中の direction に South を選択

パネルの縦幅はボタンがひとつ入る位にしておく。 7.WaterPanel を Center に追加

フレームを選択(中央をクリック)→右クリック→Add…→Add Custom →Add custom class or layout を選択

「WaterPanel」と入力して OK

名前をcenterPanel とし、Constraints の中の direction が Center になっていることを確認して OK 8.southPanel にボタンを追加

Step2 以降で使うのもだが、ここで追加しておく。

Components の一番左にある「JButton」を選んで southPanel に貼り付け 名前「resetButton」、テキスト「元に戻す」

9.ボタンが押されたときに実行されるメソッドのひな型を作成

resetButton を選択し、Event Name のリスト中の ActionListner を開いて actionPerformed を inline に設定する

10. 実行する 11. 描画を確認

(7)

-7-

3D 描画 Step1-2】

水の化学式モデルを描画する <円柱の描画・ポリゴンについて> OpenGL において例えば立方体を描画したい場合、 glut.glutWireCube(2.0f); のように関数を1つ利用すれば描画できる。このようにあらかじめ用意されている立体は、 ≪立方体・4 面体・8 面体・12 面体・20 面体・円錐・球・ドーナツ型・ティーポット≫ である。この中に円柱は含まれていないので、「ポリゴン」で表現する。 ポリゴンとは、多角形のことで、複雑なモデルを構成するために使う。CG では普通 3 角形と 4 角形を 要素として組み合わせて物体を表現する。どのような曲面も、小さいポリゴンに分割することで擬似的 に曲面として描画できる。 ポリゴンでつくられた曲面の例 今回は、原子を結ぶ線を円柱で表現する。この円柱は、円柱を縦に小さく分割するような四角形を連 続描画することで疑似的に表現する。 ポリゴンを使ったOpenGL の実際の描画は gl.glBegin(モード) ・・・ gl.glEnd() の構文で書く。主なモードは次の表のようになる。 モード 意味 GL.GL_POLYGON 凸多角形 (頂点を右回りで指定) GL.GL_LINE_STRIP 折れ線 (頂点を順次指定) GL.GL_TRIANGLE_STRIP 隣接した 3 角形 GL.GL_QUAD_STRIP 隣接した 4 角形 GL.GL_TRIANGLE_FAN 隣接した 3 角形 (扇形) gl.glBegin と gl.glEnd()の間で glVertex3f(x1, y1, z1); を何度もよびだし、頂点を順に指定していく。各モードごとの頂点の指定順は次ページの表のとおり。

(8)

-8- 頂点指定の順番 GL_TRIANGLE_STRIP GL_QUAD_STRIP GL_TRIANGLE_FAN <作成手順> WaterPanel.java に必要部分を書きたす

(9)

-9- package chemical.water; 1 2 import java.awt.event.MouseEvent; 3 import java.awt.event.MouseListener; 4 import java.awt.event.MouseMotionListener; 5 6 import javax.media.opengl.GL; 7 import javax.media.opengl.GLAutoDrawable; 8 import javax.media.opengl.GLEventListener; 9 import javax.media.opengl.GLJPanel; 10 import javax.media.opengl.glu.GLU; 11 12 import com.sun.opengl.util.GLUT; 13 14

public class WaterPanel extends GLJPanel implements GLEventListener,

15 MouseListener, MouseMotionListener { 16 17 private GL gl; // OpenGL の関数群をもつオブジェクトその1 18

private GLU glu; // OpenGL の関数群をもつオブジェクトその2

19

private GLUT glut; // OpenGL の関数群をもつオブジェクトその3

20

private int div = 20; // 球、円柱の分割数

21 22

// 軸と O-H のなす角(※水の O-H がなす角は 104.45 度)

23

private float degree = (180-104.45f)/2.0f;

24 25 /* 光 ---*/ 26 // 光の位置 {x 座標, y 座標, z 座標, 光源までの距離(0 は無限円)} 27

private float[] lPosition = { -10.0f, 10.0f, 10.0f, 0.0f };

28

// 光の色 {R, G, B, アルファ(透明度)} ※数値は 0 から 1 まで

29

private float[] lSpecular = { 0.8f, 0.8f, 0.8f, 1.0f }; // 鏡面

30

private float[] lDiffuse = { 0.8f, 0.8f, 0.8f, 1.0f }; // 拡散

31

private float[] lAmbient = { 0.4f, 0.4f, 0.4f, 1.0f }; // 環境

32 33 /* 物体の反射率 ---*/ 34 // {R, G, B, アルファ(透明度)} ※数値は 0 から 1 まで 35

private float[] mSpecular = { 0.3f, 0.3f, 0.3f, 1.0f }; // 鏡面

36

private float[] mDiffuse = { 0.2f, 0.2f, 0.2f, 1.0f }; // 拡散

37

// 鏡面係数:きらめきの度合い(0~128)

38

private float mShininess = 10.0f;

39 40 /* 色の定義 ---*/ 41 // {R, G, B, アルファ(透明度)} ※数値は 0 から 1 まで 42

private float[] blue = { 0.0f, 0.0f, 1.0f, 1.0f }; // 青

43

private float[] red = { 1.0f, 0.0f, 0.0f, 1.0f }; // 赤

44

private float[] green = {0.0f, 1.0f, 0.5f, 1.0f }; // 緑

45 46 47 /** 48 * コンストラクタ 49 */ 50 public WaterPanel() { 51 // MouseEvent を受け取れるようにする 52 addMouseListener(this); 53 // MouseMotionEvent を受け取れるようにする 54 addMouseMotionListener(this); 55 // 3D 描画できるようにリスナ登録 56 addGLEventListener(this); 57 } 58 59 60 /* 3D 描画 ************************************************************/ 61 62 /** 63 * x 軸周りに円柱を描画 64

(10)

-10-

* @param r 円柱の半径

65

* @param length 円柱の長さ

66

* @param offset offset ≦x≦offset+length に描かれる

67

*/

68

public void drawCylinder(float r, float length, float offset) {

69 double t; 70 // 要素として連続する四角形を使う 71 gl.glBegin(GL.GL_QUAD_STRIP); 72

for (int i=0; i<=div; i++) {

73 // 角度を計算(ラジアン) 74 t = 2.0 * Math.PI * i / div; 75 // 光の反射の法線ベクトル 76

gl.glNormal3f(0, (float)Math.cos(t), (float)Math.sin(t));

77

// 頂点を設定

78

gl.glVertex3f(offset, (float)(r*Math.cos(t)), (float)(r*Math.sin(t)));

79

gl.glVertex3f(offset+length, (float)(r*Math.cos(t)), (float)(r*Math.sin(t)));

80 } 81 gl.glEnd(); 82 } 83 84 /** 85 * GLEventListener のメソッド:3D 描画メソッド 86 */ 87 @Override 88

public void display(GLAutoDrawable drawable) {

89 // 背景色で塗りつぶし 90 gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); 91 // 現時点のマトリクス(Modelview 行列)を保存 ※必ず glPopMatrix()と対で使用する 92 /* glPushMatrix と glPopMatrix()は、座標を回転したり平行移動したり 93 * したものを、する前の状態を覚えておくために使う。 94 * これを使わないと、回転などがどんどん重なっていってしまう。 */ 95 gl.glPushMatrix(); 96 // z軸上 15 の位置から原点を見る,上方向は y 軸 97

// glulookat(視点の位置 x,y,z, 視点から見る座標 x,y,z, 上方向ベクトル x,y,z)

98 glu.gluLookAt(0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); 99 // y 軸正方向に少しずらす(平行移動) 100 gl.glTranslatef(0.0f, 0.4f, 0.0f); 101 102 /* 棒 1 を描画(z 軸周りに-degree 度回転)---*/ 103 // ModelView 行列保存 104 gl.glPushMatrix(); 105 // 色指定 ※環境光の反射率とは、つまり物体の色になる 106

gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, green, 0);

107 // 座標軸を z 軸周りに-degree 度回転 108 // ※2,3,4 番目の引数は回転軸を表す(順に x, y, z) 109 gl.glRotatef(-degree, 0.0f, 0.0f, 1.0f); 110 // 半径 0.07 の円柱を 0≦x≦1 に描画 111 drawCylinder(0.07f, 1.0f, 0.0f); 112 // 行列を保存した時の状態に戻す 113 gl.glPopMatrix(); 114 115 /* 棒 2 を描画(z 軸周りに degree 度回転)---*/ 116 gl.glPushMatrix(); 117

gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, green, 0);

118 gl.glRotatef(degree, 0.0f, 0.0f, 1.0f); 119 drawCylinder(0.07f, 1.0f, -1.0f); // -1≦x≦0 120 gl.glPopMatrix(); 121 122 /* O 原子を原点に描画 ---*/ 123

gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, red, 0);

124

// 塗りつぶしの球を描画

125

// glutSolidSphere(半径, Z 軸まわりの分割数, Z 軸に沿った分割数)

126

glut.glutSolidSphere(0.3, div, div);

127 128

(11)

-11-

// H 原子 1 を描画 ---*/

129

gl.glPushMatrix();

130

gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, blue, 0);

131

gl.glRotatef(-degree, 0.0f, 0.0f, 1.0f);

132

gl.glTranslatef(1.0f, 0.0f, 0.0f); // x 方向に 1 だけ平行移動

133

glut.glutSolidSphere(0.2, div, div);

134 gl.glPopMatrix(); 135 136 // H 原子 2 を描画 ---*/ 137 gl.glPushMatrix(); 138

gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, blue, 0);

139

gl.glRotatef(degree, 0.0f, 0.0f, 1.0f);

140

gl.glTranslatef(-1.0f, 0.0f, 0.0f); // x 方向に-1 だけ平行移動

141

glut.glutSolidSphere(0.2, div, div);

142 gl.glPopMatrix(); 143 144 // glPushMatrix()を呼ぶ前の行列の状態に戻す 145 gl.glPopMatrix(); 146 } 147 148 ・・・(以下は変更ないので略)・・・ 149 150 } 151

参照

関連したドキュメント

点から見たときに、 債務者に、 複数債権者の有する債権額を考慮することなく弁済することを可能にしているものとしては、

たとえば、市町村の計画冊子に載せられているアンケート内容をみると、 「朝食を摂っています か 」 「睡眠時間は十分とっていますか」

えて リア 会を設 したのです そして、 リア で 会を開 して、そこに 者を 込 ような仕 けをしました そして 会を必 開 して、オブザーバーにも必 の けをし ます

子どもたちは、全5回のプログラムで学習したこと を思い出しながら、 「昔の人は霧ヶ峰に何をしにきてい

基準の電力は,原則として次のいずれかを基準として決定するも

○池本委員 事業計画について教えていただきたいのですが、12 ページの表 4-3 を見ます と、破砕処理施設は既存施設が 1 時間当たり 60t に対して、新施設は

ƒ 、または Arduinoのリセットボタン”oƒ、2 }~x してか らコマンド @2 しま Q*した Arduino す。 プログラムを Arduino に…き:む Äsについては「

・私は小さい頃は人見知りの激しい子どもでした。しかし、当時の担任の先生が遊びを