opengl 3dcg

29
OpenGL 3DCG 大江ゼミ3年 中川武憲

Upload: takenori-nakagawa

Post on 18-Jul-2015

259 views

Category:

Technology


1 download

TRANSCRIPT

OpenGL で 3DCG大江ゼミ3年 中川武憲

Agenda

・OpenGL の基礎知識

・x,y,z 軸の描画 ・三角錐の描画 ・W,A,S,D で移動 ・マウスでカメラの向きを変更 ・三角錐の自動回転 ・デモ

OpenGL 基礎知識

・ビューイングパイプライン ・モデリング変換 ・視野変換 ・投射変換 ・ビューポート変換

OpenGL 基礎知識 ビューイング・パイプラインモデリング座標系 …モデルを基準にした座標系

(ローカル座標系)

↓                            ↓ モデリング変換

ワールド座標系 …仮想 3D 空間の基準となる座標系

↓                            ↓ 視野変換

ビュー座標系 …視点を基準とした (カメラから見た) 座標系

↓                            ↓ 投射変換

正規化デバイス座標系 … x, y, z がそれぞれ -1~1 の範囲となる座標系

(クリッピング座標系)

↓                            ↓ ビューポート変換

ウィンドウ座標系 …左上が原点、右下方向が x, y の正の方向となる2次元の座標系

(スクリーン座標系)

OpenGL 実践

x,y,z 軸の描画

GL_LINES で (0, 0, 0) から x,y,z それぞれ長さ 100 の線を引く。

各メソッドの解説glLineWidth(GLfloat width): 線幅を指定glColor4d: RGBA で色を指定 (GL_LIGHTING が disable の時のみ有効)glBegin(GLenum mode): モードを指定して頂点の追加を開始glVertex3d: XYZ で座標を指定glEnd(void): glBegin と対になる頂点グループの終わりを示す

x,y,z 軸の描画

glLineWidth(1);glDisable(GL_LIGHTING);

for (int i = 0; i < 3; i++) {int length = 100;glColor4d((i == 0), (i == 1), (i == 2), 1.0);glBegin(GL_LINES);glVertex3d(0, 0, 0);glVertex3d((i == 0) * length, (i == 1) * length, (i == 2) * length);glEnd();

}

glEnable(GL_LIGHTING);

三角錐の描画

三角錐は全ての面が三角形で構成される四面体である。頂点は4つ、辺の数は6つである。

単純に考えると、 GL_TRIANGLES で4つの三角形を描けば良いが、同じ頂点を3度指定する必要があり、合計で12個の頂点を打つことになり無駄である。

そこで、 GL_TRIANGLE_STRIP を使って合計6つの頂点で三角錐を描画した。

各メソッドの解説glNormal3d: XYZ で法線ベクトルを指定する

三角錐の描画

glBegin(GL_TRIANGLE_STRIP);glVertex3d(0, 0, 0); glNormal3d(0, 0, -1);glVertex3d(4, 0, 0); glNormal3d(0, 0, -1);glVertex3d(0, 0, 3); glNormal3d(0, 0, -1);glVertex3d(0, 2, 0); glNormal3d(0, 0, -1);glVertex3d(0, 0, 0); glNormal3d(0, 0, -1);glVertex3d(4, 0, 0); glNormal3d(0, 0, -1);glEnd();

コードでは伝わりにくい

図解

xz

y(0, 2, 0)

(4, 0, 0)(0, 0, 3)

(0, 0, 0)

図解

xz

y(0, 2, 0)

(4, 0, 0)(0, 0, 3)

(0, 0, 0)

図解

xz

y(0, 2, 0)

(4, 0, 0)(0, 0, 3)

(0, 0, 0)

図解

xz

y(0, 2, 0)

(4, 0, 0)(0, 0, 3)

(0, 0, 0)

図解

xz

y(0, 2, 0)

(4, 0, 0)(0, 0, 3)

(0, 0, 0)

何故それで描画されるのか

三角錐の展開図

三角錐の展開図 (内側→外側)c

bdc

d

a

三角錐の展開図 (外側)c

bdc

d

aGL_TRIANGLE_STRIP

W,A,S,D で移動

キーイベントに応じてワールド変換行列を操作する。

W,A,S,D で移動void keyboard(unsigned char key, int x, int y){

printf( "Key Code : %d, Position : %d %d\n", key, x, y );

// switch文を用いたキー処理の例(switch-caseを使う場合、breakの書き忘れに注意)double size = 1.0;switch(key) {

case 'a':// x 軸正方向へ移動wm[12] += size;break;

case 'd':// x 軸負方向へ移動wm[12] -= size;break;

case 'w':// z 軸正方向へ移動wm[14] += size;break;

case 's':// z 軸負方向へ移動wm[14] -= size;break;

default:printf( "\tKey: Other -> %c\n", key );

}

glutPostRedisplay();}

マウスでカメラの向きを変更

マウスイベントを拾い、ドラッグした大きさに応じてビュー変換行列を操作する。

マウスでカメラの向きを変更

void mousePressed(int button, int state, int x, int y){

printf( "Mouse Button: %d, State: %d, Position %d %d\n", button, state, x, y );

// mouse down 時if (! state) {

// 座標を記録しておくmouse_pos.x = x;mouse_pos.y = y;

}}

マウスでカメラの向きを変更void mouseDragged(int x, int y){

printf( "Mouse Drag Position %d %d\n", x, y );

pos2d diff = {mouse_pos.x - x, mouse_pos.y - y};mouse_pos.x = x;mouse_pos.y = y;

y_rad += diff.x / window.w * M_PI / 5;x_rad += diff.y / window.h * M_PI / 5;

// y 軸回転vm_y[0] = cos(y_rad);vm_y[2] = -sin(y_rad);vm_y[8] = sin(y_rad);vm_y[10] = cos(y_rad);

// x 軸回転vm_x[5] = cos(x_rad);vm_x[6] = sin(x_rad);vm_x[9] = -sin(x_rad);vm_x[10] = cos(x_rad);

// 視点の再計算resize(window.w, window.h);

glutPostRedisplay(); // ウィンドウに再描画命令を送る(ポストする)}

三角錐の自動回転

idle 関数内で定期的にワールド変換行列を操作する。

三角錐の自動回転

void idle(){

// y 軸に対して毎度 1 度ずつ右ねじ回転rad += M_PI / 180;if (rad > M_PI * 2) {

rad = 0;}

wm[0] = cos(rad);wm[2] = -sin(rad);wm[8] = sin(rad);wm[10] = cos(rad);

glutPostRedisplay(); // ウィンドウに再描画命令を送る(ポストする)}

デモ http://git.io/NnYb

描画結果

法線ベクトルの指定がおかしいので光の反射が変。

参考資料・OpenGL Documentation

https://www.opengl.org/sdk/docs/man2/xhtml/

・(Mac・iPhone)プリミティブについて - 強火で進め

http://d.hatena.ne.jp/nakamura001/20081231/1230719279

・OpenGL が世界を描画する仕組み - けんごのお屋敷

http://tkengo.github.io/blog/2014/12/27/opengl-es-2-2d-knowledge-1/

・ビジュアル情報演習 http://www.wakayama-u.ac.jp/~wuhy/08_3DCGwithGLUT.html