dx龙书有一章的题目就构建一个灵活的camera.
看了 opengl 以后,对视口变换,投影变换,模型视图变换 的顺序,关系,理解得更清晰了。
其中,视图变换相当于模型变换的逆向变换, glLookAt() 这类直接操作camera的函数,只是封装了一些逆向移动的各种 translate,rotate,scale而已。
于是自己写了一个 camera 类。
其中不足是暂时不会用 opengl 的 api 来直接计算。比如一个 vector 乘以 一个matrix,结果再保存到这个vector中,dx是有 api 的 ,我猜 opengl 可能也有。
只是自己暂时没有找到。 我也没有自己动手写这样一个函数 ,免得将来找到了,发现自己犯傻做了太多的无用功。
这个例子,纯属是为了更进一步理解 model-view 变换而写的,重点在 camera.h 和 camera.cpp,
用 camera类的 work() 函数,来取代 glLookAt() 函数。
贴出来做个笔记。
main.cpp
#include "GLFrame.h"
#include
using namespace std;
const int WINDOW_POS_X = 100;
const int WINDOW_POS_Y = 100;
const int WINDOW_SIZE_X = 800;
const int WINDOW_SIZE_Y = 600;
const string WINDOW_NAME = "solar";
int main(int arc,char** argv)
{
glutInit( &arc,argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition( WINDOW_POS_X,WINDOW_POS_Y);
glutInitWindowSize(WINDOW_SIZE_X,WINDOW_SIZE_Y);
glutCreateWindow( WINDOW_NAME.c_str() );
glutDisplayFunc( onPaintGL);
glutReshapeFunc( onReshapeGL);
//glutTimerFunc(200,onTimerGL,200);
glutMouseFunc( onMouseGL);
glutKeyboardFunc( onKeyboard );
init();
glutMainLoop();
return 0;
}
glFrame.h
#include
void init();
void onPaintGL();
void onReshapeGL(int width,int height);
void onMouseGL(int button,int state,int x,int y);
void onTimerGL(int value);
void onKeyboard(unsigned char key,int x,int y);
logic.cpp
#include "GLFrame.h"
#include
using namespace std;
#include "camera.h"
int window_width = 0;
int window_height = 0;
void paintSolar();
void paintUI();
float cur_revolution_angle = 0.0f;
float cur_autobiography_angle = 0.0f;
void revolution_earth();
void autobiography_earth();
// camera logic
static OGL_CAMERA::Camera g_camera;
enum ECameraWorkType
{
ECWT_OGL_LOOKAT,
ECWT_CUSTOM_CAMERA,
};
ECameraWorkType g_cwt = ECWT_CUSTOM_CAMERA;
void init()
{
glClearColor( 0.0,0.0,0.0,0.0);
glShadeModel( GL_FLAT );
}
void onPaintGL()
{
glClear( GL_COLOR_BUFFER_BIT );
glViewport(0,0,window_width,window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f,(GLfloat)window_width/(GLfloat)window_height,0.1,100);
glMatrixMode(GL_MODELVIEW);
if( g_cwt == ECWT_OGL_LOOKAT )
{
glLoadIdentity();
gluLookAt(0.0f,0.0f,20.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f);
}
else if( g_cwt == ECWT_CUSTOM_CAMERA)
{
g_camera.work();
}
paintSolar();
glFlush();
}
void onReshapeGL(int width,int height)
{
window_width = width;
window_height = height;
}
void onMouseGL(int button,int state,int x,int y)
{
//glutPostRedisplay();
}
void onKeyboard(unsigned char key,int x,int y)
{
switch(key)
{
case 'c':
case 'C':
cout << "camera work type changed" << endl;
g_cwt==ECWT_OGL_LOOKAT ? g_cwt = ECWT_CUSTOM_CAMERA : g_cwt = ECWT_OGL_LOOKAT;
glutPostRedisplay();
break;
}
if( g_cwt == ECWT_CUSTOM_CAMERA )
{
g_camera.processInput( key );
glutPostRedisplay();
}
}
void paintSolar()
{
glColor3f( 1.0f,0.0f,0.0f);
glPushMatrix();
{
glRotatef(cur_autobiography_angle,0,1,0);
glRotatef(90,1,0,0);
glutWireSphere(5.0f,10,10);
}
glPopMatrix();
glColor3f( 0.0f,0.0f,1.0f);
glPushMatrix();
{
glRotatef(cur_revolution_angle,0,1,0);
glTranslatef(10.0f,0.0f,0.0f);
glRotatef(cur_autobiography_angle,0,1,0);
glRotatef(90,1,0,0);
glutWireSphere(1.0f,10,10);
}
glPopMatrix();
}
void revolution_earth()
{
cur_revolution_angle += 1;
cur_revolution_angle = cur_revolution_angle > 360 ? 0 : cur_revolution_angle;
}
void autobiography_earth()
{
cur_autobiography_angle += 1.0f;
cur_autobiography_angle = cur_autobiography_angle > 360 ? 0 : cur_autobiography_angle;
}
void onTimerGL(int value)
{
revolution_earth();
autobiography_earth();
glutPostRedisplay();
glutTimerFunc(100,onTimerGL,value);
}
camera.h
#ifndef OGL_CAMERA_H
#define OGL_CAMERA_H
#include
namespace OGL_CAMERA
{
class Camera
{
protected:
GLdouble _pos[3];
GLdouble _pitch;
GLdouble _roll;
GLdouble _yaw;
//GLdouble _up[3];
//GLdouble _right[3];
//GLdouble _look[3];
protected:
void doPitch( GLdouble angle );
void doRoll( GLdouble angle );
void doYaw( GLdouble angle );
void doWalk( GLdouble dis );
void doStrafe( GLdouble dis );
void doFly( GLdouble dis );
public:
Camera();
~Camera();
void work();
void processInput(unsigned char key);
};
} // namespace OGL_CAMERA
#endif //OGL_CAMERA_H
camera.cpp
#include "camera.h"
using namespace OGL_CAMERA;
Camera::Camera()
{
_pos[0] = 0; _pos[1] = 0; _pos[2] = 20;
//_up[3] = 0; _up[1] = 1; _up[2] = 0;
//_right[0] = 1.0; _right[1] = 0; _right[2] = 0;
//_look[0]; _look[1] = 0; _look[2] = -1;
_pitch = 0;
_yaw = 0;
_roll = 0;
}
Camera::~Camera()
{
}
void Camera::processInput(unsigned char key)
{
static GLdouble angle = 5.0;
static GLdouble dis = 0.1;
switch(key)
{
// pitch
case 'w':
case 'W':
doPitch(angle);
break;
case 's':
case 'S':
doPitch(-angle);
break;
// yaw
case 'a':
case 'A':
doYaw(angle);
break;
case 'd':
case 'D':
doYaw(-angle);
break;
// roll
case 'q':
case 'Q':
doRoll(angle);
break;
case 'e':
case 'E':
doRoll(-angle);
break;
// walk
case 'i':
case 'I':
doWalk(-dis);
break;
case 'k':
case 'K':
doWalk(dis);
break;
// strafe
case 'j':
case 'J':
doStrafe(-dis);
break;
case 'l':
case 'L':
doStrafe(dis);
break;
// fly
case 'u':
case 'U':
doFly(dis);
break;
case 'o':
case 'O':
doFly(-dis);
break;
}
}
void Camera::doPitch( GLdouble angle )
{
_pitch += angle;
}
void Camera::doRoll( GLdouble angle )
{
_roll += angle;
}
void Camera::doYaw( GLdouble angle )
{
_yaw += angle;
}
void Camera::doWalk( GLdouble dis )
{
_pos[2] += dis;
}
void Camera::doStrafe( GLdouble dis )
{
_pos[0] += dis;
}
void Camera::doFly( GLdouble dis )
{
_pos[1] += dis;
}
void Camera::work()
{
glLoadIdentity();
//gluLookAt(0.0f,0.0f,10.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f);
glRotatef( -_pitch,1.0,0.0,0.0);
glRotatef( -_yaw,0.0,1.0,0.0);
glRotatef( -_roll,0.0,0.0,1.0);
glTranslatef(-_pos[0],-_pos[1],-_pos[2]);
}