3. 3D
ビューイング
1.
3Dグラフィックス処理の一般過程
2.
射影と射影変換
3.
ビューボリュームとクリッピング
4.
陰面処理とデプスバッファ
5.
ビューポート変換
6.
3Dグラフィックスを描く
7.
モデルビュー変換
1.
3Dグラフィックス処理の一般過程
1.
モデリング変換
座標系の異なる複数のオブジェクトを仮想世界に配
置し,統一的に扱うために,それぞれの座標系を
ワールド座標系に変換する
2.
ビューイング変換
ワールド座標系におけるオブジェクトの各座標系を,
視点座標系における座標値に変換する
3Dグラフィックス処理の一般過程
uvn座標系;
投影面を定義するための座標系
視点座標系のZ軸は,uvn座標系の原点を通り,uv平面と直交する
1.
正規化変換
①
x,y 成分は,
-1.0 ~ +1.0
の範囲
あるいは,
0.0 ~ +1.0
の範囲
②
z成分は,
0.0 ~ +1.0
の範囲
あるいは,
-1.0 ~ +1.0
の範囲
3Dグラフィックス処理の一般過程
1.
透視投影
1.
投影面における投影点座標の計算
投影面における投影点(x,y)座標は相似三角形理論で計算できる
投影点のx座標と点Pのx座標P
xの比,
投影点のy座標と点Pのy座標P
yの比,
投影面の距離Nと点Pの投影中心との距離-P
zの比は等しい
従って,
投影点の座標は,視点との距離に反比例する.
⇒遠いものは小さく,近いものは大きく見える
投影面の透視点の座標は投影面との距離に比例する
⇒投影される図形は投影面の距離によってスケーリングされる
しかし,射影変換された座標は最後にビューポートに変換されるので
射影される図形の大きさは結果には影響しない
射影と射影変換
z y xP
N
P
y
P
x
z y z xP
P
N
P
P
N
y
x
,
,
1.
ビューボリュームとクリッピング
OpenGL;
glFrustum(Gldouble left, Gldouble right,
Gldouble bottom, Gldouble top,
Fldouble nera, G;double far);
gluPerspective(Gldouble fovy, /* y,z
平面における視角 */
Gldouble aspect,
/* 錐台の幅対高さ比 */
Gldouble near,
Gldouble far);
正射影変換のビューボリューム
OpenGL;
glOrtho(Gldouble left,
Gldouble right,
Gldouble bottom,
Gldouble top,
Gldouble near,
Gldouble far);
ビューボリュームとクリッピング
射影中心から放射する直線上にある全ての点は同じ場所
に射影される
右図の場合,P
1がP
2に隠されているのでP
1を描く必要は
ない
隠されていることを見つける方法の1つ
視点から見る頂点の距離を利用すること,即ち遠い頂
点が近い頂点に隠される
距離の表現:デプス(depth)
--- 頂点の遠さを[-1, 1]の範囲で正規化したもの
near plane[N]; z=-1,
far plane[F]; z=1
3次元空間の点が射影変換により新たな3次元の
点にマッピングされる,
x,yは射影面の座標,zは視点からの距離
陰面処理とデプスバッファ
z zP
b
aP
z
N
F
FN
b
N
F
N
F
a
2
z z z y z x z y xP
b
aP
P
P
N
P
P
N
z
y
x
P
P
P
,
,
,
,
,
,
OpenGL depth-buffer/z-buffer
pixel
毎にデプス値を記憶する
Depth test;
frame-buffer
にある輝度あるいは色の値を更新するか否かを判断する
被射影の頂点のデプス値は現在より小さければ,そのバッファ値を更新する
処理終了時,デプスバッファの値は一番近い点の値が保存される
この結果,陰面(陰線)を除去され,見える部分のみが描画される
OpenGL;
glCLearDepthMask(Glclampd depth);
初期値を指定
glClear();
初期化
glEnable(GL_DEPTH_TEST);
デプステストを有効にする
glDepthFunc(Glenum func);
func=GL_LESS;
値が小さい場合更新
1.
ビューポート変換
一連の変換で計算される図形が最後に,この
viewport
にマッピングされる
2.
OpenGl
glViewport(GLint x, GLint y, Glsizei width, Glsizei height);
デバイス座標またはウィンドウ座標
初期値は,(0, 0, winWidth, winHeight)
注: ビューポート変換には,並行移動に加えスケーリング変換も含む
このために,図形が変形する(「ゆがみ」が生じる)
ビューポートの縦横比を near plane と同じにすると,ゆがみは生じない
ビューポート変換
1.
3Dグラフィックスを描く
program 3.1
faces;
6個の面を構成する頂点の番号を保存
カメラは,初期には原点にある
投影関係は, reshape() の中で次のように指定する
gluPerspective(60.0, (Glfloat)w/(GLfloat)h, 1.0, 20.0);
視界角fovy=60,
視点と前面,後面との距離は,1.0, 20.0
カメラ位置は原点だから,全面z=-1.0, 後面z=-20.0
reshape() は,ウィンドウを再描画する度にパラメータとして
幅wと高さhが,渡されるので,この縦横比を調整する
立方体の描画は,display()の中でDrawBox()を呼び出して行う
各面毎に,面の頂点を用いて,プリミティブGL_LINE_LOOPを指定する
3Dグラフィックスを描く
1.
モデルビュー変換 program 3.2
program 3.1
では,物体を視点座標で定義し,カメラ位置を考慮して,
物体の座標を決めている ⇒ これは不自然
モデルを移動したり,カメラ位置と視線方向を変えるモデルビュー変換により
物体は,カメラとは無関係にユーザ座標で設計できる
2.
モデリング変換・・・移動・回転・スケーリング
3.
ビューイング変換・・・カメラ位置と視線方向
モデルビュー変換
#include <stdlib.h> #include <GL/glut.h> GLint faces[6][4]={ /* 頂点番号と面の情報 */ {0,1,2,3},{3,2,6,7},{7,6,5,4},{4,5,1,0},{5,6,2,1},{7,4,0,3}}; GLfloat v[8][3]; /* 頂点座標 {x0,y0,z0}, {x1,y1,z1},….*/ void drawBox(void){ int i;
for(i=0; i<6; i++){
glBegine(GL_LINE_LOOP); glVertex3fv(&v[faces[i][0]][0]); glVertex3fv(&v[faces[i][1]][0]); glVertex3fv(&v[faces[i][2]][0]); glVertex3fv(&v[faces[i][3]][0]); glEnd(); /* pointer i/f */ } } void init(void){ glClearColor(0.0,0.0,0.0,0.0); v[0][0]=v[1][0]=v[2][0]=v[3][0]=-1; /* x-axis*/ v[4][0]=v[5][0]=v[6][0]=v[7][0]=1; v[0][1]=v[1][1]=v[4][1]=v[5][1]=-1; /* y-axis*/ v[2][1]=v[3][1]=v[6][1]=v[7][1]=1; v[0][2]=v[3][2]=v[4][2]=v[7][2]=-4; /* z-axis*/ v[1][2]=v[2][2]=v[5][2]=v[6][2]=-6; }
void display(void){
glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0);
drawBox(); glFlush(); }
void reshape(int w, int h){
glViewport(0, 0, (GLsizei)w, (GLsizei)h); glLoadIdentity();
glMatrixMode(GL_PROJECTION); /* 射影変換*/ gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); } /* camera = origine*/
/* ViewVolume w/h = ViewPort w/h*/ void keyboard(unsigned char key, int x, int y){
switch(key){ case 27; exit(0); break; } }
int main(int argc, char **argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(200, 200); glutInitWindowPosition(100, 100); glutCreatWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
3.1
0
4
3
2
7
6
5
1
#include <stdlib.h> # include <GL/glut.h> GLint faces[6][4]={ {0,1,2,3},{3,2,6,7},{7,6,5,4},{4,5,1,0},{5,6,2,1},{7,4,0,3}}; GLfloat v[8][3]; void drawBox(void){ int i;
for(i=0; i<6; i++){
glBegine(GL_LINE_LOOP); glVertex3fv(&v[faces[i][0]][0]); glVertex3fv(&v[faces[i][1]][0]); glVertex3fv(&v[faces[i][2]][0]); glVertex3fv(&v[faces[i][3]][0]); glEnd(); } } void init(void){ /* オブジェクトをユーザ座標で定義*/ glClearColor(0.0,0.0,0.0,0.0); v[0][0]=v[1][0]=v[2][0]=v[3][0]=-1; v[4][0]=v[5][0]=v[6][0]=v[7][0]=1; v[0][1]=v[1][1]=v[4][1]=v[5][1]=-1; v[2][1]=v[3][1]=v[6][1]=v[7][1]=1; v[0][2]=v[3][2]=v[4][2]=v[7][2]=1; // -4 1 v[1][2]=v[2][2]=v[5][2]=v[6][2]=-1; // -6 -1 }
void display(void){
glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glLoadIdentity(); glutLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); drawBox(); /* camera位置の設定*/ glFlush(); }
void reshape(int w, int h){
glViewport(0, 0, (GLsizei)w, (GLsizei)h); glLoadIdentity();
glMatrixMode(GL_PROJECTION);
gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y){ switch(key){ case 27; exit(0); break; } }
int main(int argc, char **argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(200, 200); glutInitWindowPosition(100, 100); glutCreatWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
3.2 モデル・ビュー変換
gluLookAt(
GLdouble eyex, GLdouble eyey, GLdouble eyez, /* camera 位置 */
GLdouble centerx, GLdouble centery, GLdouble centerz, /* cameraの注視点 */
GLdouble upx, GLdouble upy, GLdouble upz)
/* cameraの上方向 */
OpenGLにおけるカメラの設定
OpenGLにおけるカメラの設定
OpenGLにおけるモデルビュー変換の一般的な手順
1.
モデルビュー変換を指定
glMatrixMode(GL_MODELVIEW);
2.
変換マトリクスの初期化
glLoadIdentity();
3.
モデルビュウー変換
gluLookAt();
#include <stdlib.h> #include <GL/glut.h> GLint faces[6][4]={ {0,1,1,3},{3,2,6,7},{7,6,5,4},{4,5,1,0},{5,6,2,1},{7,4,0,3}}; GLfloat v[8][3]; void drawBox(void){ int i;
for(i=0; i<6; i++){
glBegine(GL_LINE_LOOP); glVertex3fv(&v[faces[i][0]][0]); glVertex3fv(&v[faces[i][1]][0]); glVertex3fv(&v[faces[i][2]][0]); glVertex3fv(&v[faces[i][3]][0]); glEnd(); } } void init(void){ glClearColor(0.0,0.0,0.0,0.0); v[0][0]=v[1][0]=v[2][0]=v[3][0]=-1; v[4][0]=v[5][0]=v[6][0]=v[7][0]=1; v[0][1]=v[1][1]=v[4][1]=v[5][1]=-1; v[2][1]=v[3][1]=v[6][1]=v[7][1]=1; v[0][2]=v[3][2]=v[4][2]=v[7][2]=1; v[1][2]=v[2][2]=v[5][2]=v[6][2]=-1; } viod LookAt(void){ /* 視点の変化に対するビューアップベクトルの計算*/ int i;
GLdouble look[3], norm;
GLdouble ViewAt[3] = {5.0, 7.5, 5.0}; /* 位置 */ GLdouble ViewTo[3] = {0.0, 0.0, 0.0}; /* 注視方向 */ GLdouble ViewUp[3]; /* 上方向 */ for(i=0; i<3; i++){
look[i] =ViewTo[i] - ViewAt[i]; }
ViewUp[0] = - look[0] * look[2]; ViewUp[1] = - look[1] * look[2];
ViewUp[2] = look[0] * look[0] + look[1] * look[1] + look[2] * look[2];
norm = ViewUp[0]*ViewUp[0] + ViewUp[1]*ViewUp[1] + ViewUp[2]*ViewUp[2]; norm = sqrt(norm);
for(i=0; i<3; i++){
ViewUp[i] /= norm; }
gluLookAt(ViewAt[0], ViewAt[1], ViewAt[2], ViewTo[0], ViewTo[1], ViewTo[2], ViewUp[0], ViewUp[1], ViewUp[2]);
} void display(void){ glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glLoadIdentity(); LookAt(); drawBox(); glFlush(); }
3.3 視点を変化
void reshape(int w, int h){
glViewport(0, 0, (GLsizei)w, (GLsizei)h); glLoadIdentity();
glMatrixMode(GL_PROJECTION);
gluPerspective(30.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y){ switch(key){ case 27; exit(0); break; } }
int main(int argc, char **argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(200, 200); glutInitWindowPosition(100, 100); glutCreatWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
3.3
#include <stdlib.h> #include <GL/glut.h> GLint faces[6][4]={ {0,1,1,3},{3,2,6,7},{7,6,5,4}, {4,5,1,0},{5,6,2,1},{7,4,0,3}}; GLfloat v[8][3]; GLfloat n[6][3]={ {-1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{1.0, 0.0, 0.0}, {0.0, -1.0, 0.0},{0.0, 0.0, -1.0},{0.0, 0.0, 1.0}}; void drawBox(void){ int i;
for(i=0; i<6; i++)
glBegin(GL_POLYGON); glNormal3fv(&n[i][0]); glVertex3fv(&v[faces[i][0]][0]); glVertex3fv(&v[faces[i][1]][0]); glVertex3fv(&v[faces[i][2]][0]); glVertex3fv(&v[faces[i][3]][0]); glEnd(); } } void init(void){ GLfloat mat_amb_diff[4]={1.0,1.0,1.0,1.0}; GLfloat light_amb[4]={1.0,5.5,1.0,1.0}; glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_SMOOTH);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_amb_diff);
glLightfv(GL_LIGHT0, GL_POSITION, light_amb);
glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); v[0][0]=v[1][0]=v[2][0]=v[3][0]=-1; v[4][0]=v[5][0]=v[6][0]=v[7][0]=1; v[0][1]=v[1][1]=v[4][1]=v[5][1]=-1; v[2][1]=v[3][1]=v[6][1]=v[7][1]=1; v[0][2]=v[3][2]=v[4][2]=v[7][2]=1; v[1][2]=v[2][2]=v[5][2]=v[6][2]=-1; } viod LookAt(void){ /* 視点の変化に対するビューアップベクトルの計算*/ int i;
GLdouble look[3], norm;
GLdouble ViewAt[3] = {5.0, 7.5, 5.0}; /* 位置 */ GLdouble ViewTo[3] = {0.0, 0.0, 0.0}; /* 注視方向 */ GLdouble ViewUp[3]; /* 上方向 */ for(i=0; i<3; i++){
look[i] =ViewTo[i] - ViewAt[i]; }
ViewUp[0] = - look[0] * look[2]; ViewUp[1] = - look[1] * look[2];
ViewUp[2] = look[0] * look[0] + look[1] * look[1] + look[2] * look[2];
norm = ViewUp[0]*ViewUp[0] + ViewUp[1]*ViewUp[1] + ViewUp[2]*ViewUp[2]; norm = sqrt(norm);
for(i=0; i<3; i++){
ViewUp[i] /= norm; }
gluLookAt(ViewAt[0], ViewAt[1], ViewAt[2], ViewTo[0], ViewTo[1], ViewTo[2], ViewUp[0], ViewUp[1], ViewUp[2]);
}
void display(void){ glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glLoadIdentity(); LookAt(); drawBox(); glFlush(); }
void reshape(int w, int h){
glViewport(0, 0, (GLsizei)w, (GLsizei)h); glLoadIdentity(); glMatrixMode(GL_PROJECTION); gluPerspective(30.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); glClear(GL_DEPTH_BUFFER_BIT); }
void keyboard(unsigned char key, int x, int y){ switch(key){ case 27; exit(0); break; } }
int main(int argc, char **argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(200, 200); glutInitWindowPosition(100, 100); glutCreatWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }