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

このような 回転や平行移動による座標変換の情報は ModelView 行列 が持っている ModelView 行列は gl.glpushmatrix() でいったん保存しておき 回転や平行移動を重ねて描画した後 gl.glpopmatrix() で保存した状態に戻すことができる ワールド座標系とウィ

N/A
N/A
Protected

Academic year: 2021

シェア "このような 回転や平行移動による座標変換の情報は ModelView 行列 が持っている ModelView 行列は gl.glpushmatrix() でいったん保存しておき 回転や平行移動を重ねて描画した後 gl.glpopmatrix() で保存した状態に戻すことができる ワールド座標系とウィ"

Copied!
8
0
0

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

全文

(1)

-1-

3D 描画 Step3】

元素名を2D 描画する OpenGL には文字描画の概念がないこと、元素名は回転してほしくないことの 2 点の理由から、元素 名は2D 描画する。そのために、原子の 3 次元空間の座標から、文字を描画するウィンドウ上の座標を求 める。 <座標変換について> ※座標変換について、まとまった詳しい解説は「OpenGL による 3D 描画の基礎知識」の 3 ページ以 降に記述してあるので、参照のこと。 ワールド座標系の軸 ◆オブジェクト座標系とワールド座標系 O 原子も H 原子も描画するときは

glut.glutSolidSphere(0.2f, div, div); ………(*)

と記述する。引数は順に半径、Z 軸まわりの分割数、Z 軸に沿った分割数で、球の中心座標を設定する引 数はない。これは、常にこの関数が球の中心を原点として描画するからである。この場合の座標系が「オ ブジェクト座標系」となる。 しかし、図のように実際にワールド座標系で考えればO 原子の中心座標は (0, 0.4, 0) だし、右側の H 原子は (cosθ, 0.4-sinθ, 0) [※θ=(180°-104.45°)/2] である。このような位置に描画するため には、描画したい球の中心が原点になるよう事前にglTranslatef や glRotatef で座標変換しておく。 例えば、O 原子の場合、 gl.glTranslatef(0.0f, 0.4f, 0.0f); // y 軸正方向に 0.4 平行移動 を実行した後で(*)の球の描画命令を書けばよい。また、右側の H 原子は 上記の0.4 の平行移動が利いた状態でさらに以下を実行する gl.glRotatef(-degree, 0.0f, 0.0f, 1.0f); // 座標軸を z 軸周りに-degree 度回転 gl.glTranslatef(1.0f, 0.0f, 0.0f); // x 軸正方向に 1 だけ平行移動 104.45° x 軸 y 軸 z 軸 θ θに相当する

(2)

-2- 「ModelView 行列」 が持っている。ModelView 行列は、gl.glPushMatrix()でいったん保存しておき、回転や平行移動を重ね て描画した後、gl.glPopMatrix()で保存した状態に戻すことができる。 ◆ワールド座標系とウィンドウ座標系 3 次元空間であるワールド座標から、2 次元の表示領域に対する座標をもとめるには、 「Projectioin 行列」 を使う。この行列は、3D からどのように 2D に投影するかを決めるものである。 また、パネルに対する表示領域を「ビューポート」といい、4 次元の配列で表現する。 ビューポート=[左下の点の x 座標, y 座標, 幅, 高さ] ◆オブジェクト座標系からウィンドウ座標系への変換 OpenGL には便利な関数があって、

glu.gluProject(objx, objy, objz, modelMatrix, 0, projMatrix, 0, viewport, 0, winPos, 0); objx, objy, objz:3D 空間の x 座標、y 座標、z 座標(オブジェクト座標系) modelMatrix:ModelView 行列 projMatrix:Projection 行列 viewport:ビューポート を呼び出すとwinPos(double の配列)にビューポートの左下を原点とする、右・上が正方向の 2 次元 ピクセルの単位での座標がはいる。つまりオブジェクト座標系からウィンドウ座標系に変換してくれる。 しかし、描画するにはパネルの左上を原点とした、下向きが正の座標でなければならないので、今回 は上記の関数で求めた座標をさらに変換する。下記のソースコードはこの変換部分が空欄になっている ので、下図を参考に考えて埋めなさい。 <作成手順> 1.WaterPanel.java を編集する。 2.実行して元素名O,H が正常に描画されることを確認する ビューポート glu.gluProjectで求まる 座標の原点 描画で必要な 座標の原点 viewport[0] getHeight() viewport[3] viewport[1] viewport[2]

(3)

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

public class WaterPanel extends GLJPanel implements GLEventListener, 19 MouseListener, MouseMotionListener { 20 21 private GL gl; // OpenGL の関数群をもつオブジェクトその1 22

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

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

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

26

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

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

29

private float rotx = 0.0f, roty = 0.0f; // 回転量 30

private float sRotx, sRoty; // ドラッグ開始時の回転量 31

private Point startPoint, endPoint; // ドラッグの開始点と終了点 32

private boolean defaultFlg = true; // true だったら回転量を 0 にする 33

34

private double[] model = new double[16]; // ModelView 行列 35

private double[] proj = new double[16]; // Projection 行列 36

private int[] view = new int[4]; // ビューポート 37

private double[] pointO = new double[3]; // O 原子のウィンドウ座標 38

private double[] pointH1 = new double[3]; // H 原子 1 のウィンドウ座標 39

private double[] pointH2 = new double[3]; // H 原子 2 のウィンドウ座標 40 41 /* 光 ---*/ 42 // 光の位置 {x 座標, y 座標, z 座標, 光源までの距離(0 は無限円)} 43

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

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

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

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

private float[] lAmbient = { 0.4f, 0.4f, 0.4f, 1.0f }; // 環境 48 49 /* 物体の反射率 ---*/ 50 // {R, G, B, アルファ(透明度)} ※数値は 0 から 1 まで 51

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

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

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

private float mShininess = 10.0f; 55 56 /* 色の定義 ---*/ 57 // {R, G, B, アルファ(透明度)} ※数値は 0 から 1 まで 58

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

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

private float[] green = {0.0f, 1.0f, 0.5f, 1.0f }; // 緑 61 62 /** 63 * コンストラクタ 64

(4)

-4- */ 65 public WaterPanel () { 66 // MouseEvent を受け取れるようにする 67 addMouseListener(this); 68 // MouseMotionEvent を受け取れるようにする 69 addMouseMotionListener(this); 70 // 3D 描画できるようにリスナ登録 71 addGLEventListener(this); 72 } 73 74 /* 2D 描画 ************************************************************/ 75 @Override 76

public void paintComponent(Graphics g) { 77 // 親クラスの paintComponent 呼び出し 78 super.paintComponent(g); 79 // フォント設定 ※Dialog は Windows では MS ゴシック 80

g.setFont(new Font("Dialog", Font.BOLD, 24)); 81 // 白色設定 82 g.setColor(Color.WHITE); 83 // 文字位置の微調整用 84 int tune = 8; 85 // 元素名を描画 86

g.drawString("O", (int)pointO[0]-tune, (int)pointO[1]+tune); 87

g.drawString("H", (int)pointH1[0]-tune, (int)pointH1[1]+tune); 88

g.drawString("H", (int)pointH2[0]-tune, (int)pointH2[1]+tune); 89 } 90 91 /* 3D 描画 ************************************************************/ 92 93 /** 94 * x 軸周りに円柱を描画 95 * @param r 円柱の半径 96 * @param length 円柱の長さ 97

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

*/ 99

public void drawCylinder(float r, float length, float offset) { 100 double t; 101 // 要素として連続する四角形を使う 102 gl.glBegin(GL.GL_QUAD_STRIP); 103

for (int i=0; i<=div; i++) { 104 // 角度を計算(ラジアン) 105 t = 2.0 * Math.PI * i / div; 106 // 光の反射の法線ベクトル 107

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

// 頂点を設定 109

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

gl.glVertex3f(offset+length, (float)(r*Math.cos(t)), (float)(r*Math.sin(t))); 111 } 112 gl.glEnd(); 113 } 114 115 /** 116 * オブジェクト座標から、ウィンドウ座標を求める 117 */ 118

public boolean gluProject(double objx, 119 double objy, 120 double objz, 121 double[] modelMatrix, 122 double[] projMatrix, 123 int[] viewport, 124 double[] winPos ) { 125 /* gluProject:3D空間のx座標,y座標,z座標,ModelView行列,Projection行列,ビューポートを使って 126 * ウィンドウ座標を求める。 127 * ただし、ビューポート(描画領域)の左下が原点、y 座標上向き */ 128

(5)

WaterPanel.java

-5- boolean bl = glu.gluProject(objx, objy, objz, 129

modelMatrix, 0, projMatrix, 0, viewport, 0, winPos, 0); 130 winPos[0] += viewport[0]; 131 // パネルの左上を原点とする y 座標下向きに変換 132 // ※viewport の中身は[左下の x 座標, y 座標, ビューポート(描画領域)の幅, 高さ] 133

winPos[1] = getHeight() - viewport[1] - winPos[1]; 134 return bl; 135 } 136 137 /** 138 * GLEventListener のメソッド:3D 描画メソッド 139 */ 140 @Override 141

public void display(GLAutoDrawable drawable) { 142 /* deaultFlg=true なら最初かリセットボタンが押された状態 143 * なので、回転量を 0 にするs */ 144 if (defaultFlg) { 145 rotx = 0.0f; 146 roty = 0.0f; 147 defaultFlg = false; 148 } 149 150 // 背景色で塗りつぶし 151 gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); 152 // 現時点のマトリクス(Modelview 行列)を保存 ※必ず glPopMatrix()と対で使用する 153 /* glPushMatrix と glPopMatrix()は、座標を回転したり平行移動したり 154 * したものを、する前の状態を覚えておくために使う。 155 * これを使わないと、回転などがどんどん重なっていってしまう。 */ 156 gl.glPushMatrix(); 157 // z軸上 15 の位置から原点を見る,上方向は y 軸 158

// glulookat(視点の位置 x,y,z, 視点から見る座標 x,y,z, 上方向ベクトル x,y,z) 159 glu.gluLookAt(0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); 160 // マウスの移動量に応じて回転 161 gl.glRotatef(rotx, 1.0f, 0.0f, 0.0f); 162 gl.glRotatef(roty, 0.0f, 1.0f, 0.0f); 163 // y 軸正方向に少しずらす 164 gl.glTranslatef(0.0f, 0.4f, 0.0f); 165 166 /* 棒 1 を描画(z 軸周りに-degree 度回転)---*/ 167 // ModelView 行列保存 168 gl.glPushMatrix(); 169 // 色指定 170 // ※環境光の反射率とは、つまり物体の色になる 171

gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, green, 0); 172 // 座標軸を z 軸周りに-degree 度回転 173 // ※2,3,4 番目の引数は回転軸を表す(順に x, y, z) 174 gl.glRotatef(-degree, 0.0f, 0.0f, 1.0f); 175 // 半径 0.07 の円柱を 0≦x≦1 に描画 176 drawCylinder(0.07f, 1.0f, 0.0f); 177 // 行列を保存した時の状態に戻す 178 gl.glPopMatrix(); 179 180 /* 棒 2 を描画(z 軸周りに degree 度回転)---*/ 181 gl.glPushMatrix(); 182

gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, green, 0); 183 gl.glRotatef(degree, 0.0f, 0.0f, 1.0f); 184 drawCylinder(0.07f, 1.0f, -1.0f); // -1≦x≦0 185 gl.glPopMatrix(); 186 187 /* O 原子を原点に描画 ---*/ 188

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

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

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

glut.glutSolidSphere(0.3, div, div); 192

(6)

-6- // ModelView 行列を取得 193 gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, model, 0); 194 // O 原子のウィンドウ座標を取得 195

gluProject(0.0, 0.0, 0.0, model, proj, view, pointO); 196 197 // H 原子 1 を描画 ---*/ 198 gl.glPushMatrix(); 199

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

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

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

glut.glutSolidSphere(0.2, div, div); 203

gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, model, 0); // ModelView 行列を取得 204

gluProject(0.0, 0.0, 0.0, model, proj, view, pointH1); 205 gl.glPopMatrix(); 206 207 // H 原子 2 を描画 ---*/ 208 gl.glPushMatrix(); 209

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

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

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

glut.glutSolidSphere(0.2, div, div); 213

gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, model, 0); // ModelView 行列を取得 214

gluProject(0.0, 0.0, 0.0, model, proj, view, pointH2); 215 gl.glPopMatrix(); 216 217 // glPushMatrix()を呼ぶ前の行列の状態に戻す 218 gl.glPopMatrix(); 219 } 220 221 /** 222 * GLEventListener のメソッド:表示の切り替えが発生した場合に呼ばれる 223 * 今回は特に記述することはない 224 */ 225 @Override 226

public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, 227 boolean deviceChanged) { 228 } 229 230 /** 231 * GLEventListener のメソッド:初期化時に呼ばれる 232 */ 233 @Override 234

public void init(GLAutoDrawable drawable) { 235

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

gl = drawable.getGL(); 237

glu = new GLU(); 238

glut = new GLUT(); 239 // 背景色を黒に設定 240 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 241 // 影に隠れて見えないものは表示しない 242 gl.glEnable(GL.GL_DEPTH_TEST); 243 // 光を有効にする 244 gl.glEnable(GL.GL_LIGHTING); 245 gl.glEnable(GL.GL_LIGHT0); 246 // 光の反射の法線ベクトルを正規化 247 gl.glEnable(GL.GL_NORMALIZE); 248 // 光の位置を設定 249 /* 4 番目の数字はオフセット。 250 * JOGL は c++のソースを JAVA に自動変換している。 251 * c++では配列はポインタなので、オフセットの概念がある 252 * JAVA にポインタはないので引数が増やされているのだが、 253 * オフセットの数字は 0 でよい。 */ 254

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

// 光の色を設定 256

(7)

WaterPanel.java

-7-

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

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

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

// 物体の反射率を設定 260

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

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

gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, mShininess); // 鏡面係数 263 } 264 265 /** 266 * GLEventListener のメソッド:表示領域が変更されたときに呼ばれる 267 */ 268 @Override 269

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

int height) { 271

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

gl.glViewport(0, 0, width, height); 273 // マトリクスとして Projection 行列を対象にする 274 gl.glMatrixMode(GL.GL_PROJECTION); 275 // マトリクスを単位行列で初期化 276 gl.glLoadIdentity(); 277 // 視点の設定(参考資料を参照) 278

// gluPerspactive(視野角, 縦横比, near, far); 279 glu.gluPerspective(10.0, (double)width/(double)height, 1.0, 100.0); 280 // マトリクスとして ModelView 行列を対象にする 281 gl.glMatrixMode(GL.GL_MODELVIEW); 282 // Projection 行列取得 283 gl.glGetDoublev(GL.GL_PROJECTION_MATRIX, proj, 0); 284 // ビューポート取得 285 gl.glGetIntegerv(GL.GL_VIEWPORT, view, 0); 286 } 287 288 /* MouseListener のメソッド **************************************************/ 289 290 @Override 291

public void mouseClicked(MouseEvent e) { 292

// TODO Auto-generated method stub 293 294 } 295 296 @Override 297

public void mouseEntered(MouseEvent e) { 298

// TODO Auto-generated method stub 299 300 } 301 302 @Override 303

public void mouseExited(MouseEvent e) { 304

// TODO Auto-generated method stub 305 306 } 307 308 /** 309 * マウスを押したらスタートポイントに設定 310 */ 311 @Override 312

public void mousePressed(MouseEvent e) { 313 // マウスを押した場所を取得 314 startPoint = e.getPoint(); 315 // 現時点での回転量を保存 316 sRotx = rotx; 317 sRoty = roty; 318 } 319 320

(8)

-8- @Override

321

public void mouseReleased(MouseEvent e) { 322

// TODO Auto-generated method stub 323 324 } 325 326 /* MouseMotionListener のメソッド *************************************************/ 327 328 /** 329 * ドラッグで回転量を計算 330 */ 331 @Override 332

public void mouseDragged(MouseEvent e) { 333 // マウスの場所を取得 334 endPoint = e.getPoint(); 335 // 回転量を計算(パネルの端から端で一回転) 336

rotx = sRotx + 360.0f*(float)(endPoint.y - startPoint.y)/(float)getWidth(); 337

roty = sRoty + 360.0f*(float)(endPoint.x - startPoint.x)/(float)getHeight(); 338 // 再描画 339 repaint(); 340 } 341 342 @Override 343

public void mouseMoved(MouseEvent e) { 344

// TODO Auto-generated method stub 345 346 } 347 348 /* defaultFlg の setter ***************************************************************/ 349

public void setDefaultFlg(boolean defaultFlg) { 350 this.defaultFlg = defaultFlg; 351 } 352 353 354 } 355

参照

関連したドキュメント

(15) 特定口座を開設している金融機関に、NISA口座(少額投資非課税制度における非

図一1 に示す ような,縦 お よび横 補剛材 で補 剛 された 板要素か らなる断面部材 の全 体剛性 行列 お よび安定係数 行列は局所 座標 系で求 め られた横補 剛材

め測定点の座標を決めてある展開図の応用が可能であ

活動後の評価    心構え   

Mapping Satoshi KITAYAMA and Hiroshi YAMAKAWA Waseda University,Dept.of Mech.Eng.,59‑314,3‑4‑1,Ohkubo,Shinjuku‑ku Tokyo,169‑8555 Japan This paper presents a method to determine

私たちの行動には 5W1H

ベクトル計算と解析幾何 移動,移動の加法 移動と実数との乗法 ベクトル空間の概念 平面における基底と座標系

tiSOneと共にcOrtisODeを検出したことは,恰も 血漿中に少なくともこの場合COTtisOIleの即行