OpenGLでカメラ設定
カメラの位置
カメラは描画のはじめにやればよさそう。
// setup view glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt( -30.0f, 30.0f, -30.0f, centerX, centerY, centerZ, 0.5f, 0.5f, 0.5f);
gluLookAt関数がカメラの設定をしており、
- 1行目の(30.0f, 30.0f, 30.0f)はカメラの位置
- 2行目の(centerX, centerY, centerZ)はカメラが見つめている先の位置
- 3行目の(0.5f, 0.5f, 0.5f)はカメラの頭の方向を表すベクトル
を表している。詳しくは下記のサイト参照。
http://homepage3.nifty.com/li-chu/OpenGL/OpenGL04.html#look
頭の方向のベクトルについては大きさはそこまで関係ない?比率が大事っぽい。
サンプル
キーボード入力のテストも兼ねて、視線の位置を変更させるプログラム作ったので載せとく。
/* -*- coding:utf-8 -*- */ /** * opengl_lookat.cpp */ #include <SDL.h> #include <SDL_opengl.h> #include <OpenGL/glu.h> #include <iostream> #include <string> #include <cmath> static const std::string WINDOW_CAPTION = "SDL with OpenGL : lookat test"; static const Uint32 WINDOW_WIDTH = 640; static const Uint32 WINDOW_HEIGHT = 480; static const Uint32 WINDOW_BPP = 32; static const GLdouble SIGHT_ANGLE = 45.0; static const GLdouble SIGHT_NEAR = 2.0; static const GLdouble SIGHT_FAR = 200.0; static const Uint32 FPS = 60; static SDL_Window* window; static SDL_GLContext context; static GLfloat centerX = 0.0f; static GLfloat centerY = 0.0f; static GLfloat centerZ = 0.0f; bool init(); bool finalize(); void update(); void draw(); void drawGrid(); void drawCenter(); bool pollingEvent(); int main(int argc, char** argv) { // initialize if (!init()) { std::cerr << "ERROR: failed to initialize SDL" << std::endl; exit(1); } // mainloop static const Uint32 interval = 1000 / FPS; static Uint32 nextTime = SDL_GetTicks() + interval; bool skipDraw = false; while (true) { // check event if (!pollingEvent()) break; // update and draw update(); if (!skipDraw) { draw(); SDL_GL_SwapWindow(window); } int delayTime = (int)(nextTime - SDL_GetTicks()); if (delayTime > 0) { SDL_Delay((Uint32)delayTime); skipDraw = false; } else { // skip next draw step because of no time skipDraw = true; } nextTime += interval; } // finalize finalize(); return 0; } bool init() { // initialize SDL if( SDL_Init(SDL_INIT_VIDEO) < 0 ) return false; // enable double buffering SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // create indow // set SDL_WINDOW_OPENGL to use opengl for drawing window = SDL_CreateWindow(WINDOW_CAPTION.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL); if (!window) return false; // create OpenGL context context = SDL_GL_CreateContext(window); if (!context) return false; // setup viewport glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glEnable(GL_DEPTH_TEST); // setup projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLdouble aspect = (GLdouble) WINDOW_WIDTH / (GLdouble) WINDOW_HEIGHT; gluPerspective(SIGHT_ANGLE, aspect, SIGHT_NEAR, SIGHT_FAR); return true; } bool finalize() { // finalize SDL SDL_Quit(); return true; } void update() { } void draw() { // clear glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // setup view glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt( -30.0f, 30.0f, -30.0f, centerX, centerY, centerZ, 0.5f, 0.5f, 0.5f); // draw grid lines drawGrid(); // draw center point drawCenter(); glFlush(); } void drawGrid() { // z-axis glBegin(GL_LINES); { glLineWidth(5.0f); glColor3d(0.0, 1.0, 1.0); glVertex3d(0, 0, -250.0); glVertex3d(0, 0, 250.0); } glEnd(); for (GLint x=-5; x<=5; x++) { glBegin(GL_LINES); { glColor3d(1.0, 1.0, 1.0); glVertex3d(x, 0, -5.0); glVertex3d(x, 0, 5.0); } glEnd(); } // x-axis glBegin(GL_LINES); { glLineWidth(5.0f); glColor3d(1.0, 0.0, 1.0); glVertex3d(-250, 0, 0); glVertex3d(250, 0, 0); } glEnd(); for (GLint z=-5; z<=5; z++) { glBegin(GL_LINES); { glColor3d(1.0, 1.0, 1.0); glVertex3d(-5.0, 0, z); glVertex3d(5.0, 0, z); } glEnd(); } // y-axis glBegin(GL_LINES); { glLineWidth(5.0f); glColor3d(1.0, 1.0, 0.0); glVertex3d(0, -250, 0); glVertex3d(0, 250, 0); } glEnd(); } void drawCenter() { glPointSize(10.0f); glColor3d(1.0, 0.0, 0.0); glBegin(GL_POINTS); { glVertex3f(centerX, centerY, centerZ); } glEnd(); } // polling event and execute actions bool pollingEvent() { SDL_Event ev; SDL_Keycode key; while ( SDL_PollEvent(&ev) ) { switch(ev.type){ case SDL_QUIT: // raise when exit event is occur return false; break; case SDL_KEYDOWN: // raise when key down { key = ev.key.keysym.sym; // ESC if(key == SDLK_ESCAPE){ return false; } // UP if(key == SDLK_UP){ centerZ += 1.0f; } // DOWN if(key == SDLK_DOWN){ centerZ -= 1.0f; } // LEFT if(key == SDLK_LEFT){ centerX += 1.0f; } // RIGHT if(key == SDLK_RIGHT){ centerX -= 1.0f; } // u if(key == SDLK_u){ centerY += 1.0f; } // d if(key == SDLK_d){ centerY -= 1.0f; } // r if(key == SDLK_r){ centerX = 0.0f; centerY = 0.0f; centerZ = 0.0f; } } break; } } return true; }
コンパイルは下記の通り。
g++ -o opengl_lookat opengl_lookat.cpp `sdl2-config --cflags` `sdl2-config --libs` -framework GLUT -framework OpenGL
実行すると下のようになる。紫色の線はx軸、黄色の線はy軸、水色の線はz軸を表している。白いグリッド船はxz平面上に間隔1.0で引いてある。中心の赤い点は視線の先で、さっきの(centerX, centerY, centerZ)の位置。
キーボードで視点の位置が変化する。詳細は以下の通り。
- 上矢印 : z軸方向に1進む
- 下矢印 : z軸方向に-1進む
- 左矢印 : x軸方向に1進む
- 右矢印 : x軸方向に-1進む
- u : y軸方向に1進む
- d : y軸方向に-1進む
- r : 視線の先の座標を(0,0,0)に戻す