使用gluLookAt確定攝像機(jī)位置
函數(shù)原型
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);
參數(shù)說明
第一組eyex, eyey,eyez 相機(jī)在世界坐標(biāo)的位置
第二組centerx,centery,centerz 相機(jī)鏡頭對準(zhǔn)的物體在世界坐標(biāo)的位置
第三組upx,upy,upz 相機(jī)向上的方向在世界坐標(biāo)中的方向
攝像機(jī)移動
攝像機(jī)移動時(shí),在自身坐標(biāo)系中的朝向并不改變,因此只需要改變攝像機(jī)在世界坐標(biāo)系中的位置坐標(biāo)即可。
攝像機(jī)旋轉(zhuǎn)
關(guān)于OpenGL坐標(biāo)系,簡單地說就是窗口中心是原點(diǎn),水平向右是x軸正方向,垂直向上是y軸正方向,垂直屏幕向外是z軸正方向。
攝像機(jī)方向與xOy平面,xOz平面,yOz平面都會呈一定的角度。
在攝像機(jī)旋轉(zhuǎn)時(shí),攝像機(jī)位置不改變,僅改變朝向。

- pitch是圍繞X軸旋轉(zhuǎn),也叫做俯仰角
- yaw是圍繞Y軸旋轉(zhuǎn),也叫偏航角
- roll是圍繞Z軸旋轉(zhuǎn),也叫翻滾角
如圖,攝像機(jī)的旋轉(zhuǎn)有俯仰(pitch),偏航(yaw)和翻滾(roll)三種方式。
攝像機(jī)實(shí)現(xiàn)
class Camera
{
public:
Camera();
float camera_x, camera_y, camera_z; // 攝像機(jī)位置坐標(biāo)
float lookat_x, lookat_y, lookat_z; // 攝像機(jī)朝向坐標(biāo)
void YawCamera(float fAngle); // yaw方法
void PitchCamera(float fAngle); // pitch方法
void WalkStraight(float fSpeed); // 前后移動方法
void WalkTransverse(float fSpeed); // 左右移動方法
float angle; // 每次旋轉(zhuǎn)角度
float speed; // 每次移動距離
float sight; // 視野
float rad_yz, rad_xz; // 攝像機(jī)朝向與yOz平面,xOz平面所成弧度
float rotate_yz, rotate_xz; //攝像機(jī)朝向與yOz平面,xOz平面所成角度
float PI;
};
由于操作按鍵(WASD與方向鍵)的原因,沒有實(shí)現(xiàn)roll方法與上下移動方法。
Camera::Camera() // 攝像機(jī)的構(gòu)造函數(shù)
{
PI = 3.1415;
angle = 3;
speed = 0.3;
sight = 100;
rotate_yz = 0.0f;
rotate_xz = -90.0f;
rad_yz = rotate_yz*PI / 180.0f;
rad_xz = rotate_xz*PI / 180.0f;
camera_x = 0.0f;
camera_y = 0.0f;
camera_z = 8.0f;
lookat_x = camera_x + sight*cos(rad_yz)*cos(rad_xz);
lookat_y = camera_y + sight*sin(rad_yz);
lookat_z = camera_z + sight*cos(rad_yz)*sin(rad_xz);
}
void Camera::YawCamera(float fAngle) // yaw方法實(shí)現(xiàn)
{
rotate_xz = (int)(rotate_xz + fAngle) % 360;
rad_xz = rotate_xz*PI / 180.0f;
lookat_x = camera_x + sight*cos(rad_yz)*cos(rad_xz);
lookat_y = camera_y + sight*sin(rad_yz);
lookat_z = camera_z + sight*cos(rad_yz)*sin(rad_xz);
}
void Camera::PitchCamera(float fAngle) // pitch方法實(shí)現(xiàn)
{
rotate_yz = (int)(rotate_yz + fAngle) % 360;
rad_yz = rotate_yz*PI / 180.0f;
lookat_x = camera_x + sight*cos(rad_yz)*cos(rad_xz);
lookat_y = camera_y + sight*sin(rad_yz);
lookat_z = camera_z + sight*cos(rad_yz)*sin(rad_xz);
}
void Camera::WalkStraight(float fSpeed) // 前后移動方法實(shí)現(xiàn)
{
camera_x += fSpeed*cos(rad_yz)*cos(rad_xz);
camera_y += fSpeed*sin(rad_yz);
camera_z += fSpeed*cos(rad_yz)*sin(rad_xz);
lookat_x = camera_x + sight*cos(rad_yz)*cos(rad_xz);
lookat_y = camera_y + sight*sin(rad_yz);
lookat_z = camera_z + sight*cos(rad_yz)*sin(rad_xz);
}
void Camera::WalkTransverse(float fSpeed) // 左右移動方法實(shí)現(xiàn)
{
camera_x += fSpeed*cos(rad_yz)*sin(rad_xz);
camera_z -= fSpeed*cos(rad_yz)*cos(rad_xz);
lookat_x = camera_x + sight*cos(rad_yz)*cos(rad_xz);
lookat_y = camera_y + sight*sin(rad_yz);
lookat_z = camera_z + sight*cos(rad_yz)*sin(rad_xz);
}
相關(guān)計(jì)算方法就是高中數(shù)學(xué)的立體幾何+三角函數(shù)知識
在OpenGL中實(shí)現(xiàn)
#include <stdlib.h>
#define GLUT_DISABLE_ATEXIT_HACK
#include <glut.h>
#include "Camera.h"
int window_width = 640;
int window_height = 480;
Camera camera;
void setProjection()
{
if (0 == window_height)
{
window_height = 1;
}
double ratio = 1.0 * window_width / window_height;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, ratio, 0.01, 100);
glViewport(0, 0, window_width, window_height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(camera.camera_x, camera.camera_y, camera.camera_z, camera.lookat_x, camera.lookat_y, camera.lookat_z, 0.0f, 1.0f, 0.0f);
}
void setLight()
{
GLfloat ambient[] = { 1.0,1.0,1.0,1.0 };
GLfloat diffuse[] = { 1.0,1.0,1.0,1.0 };
GLfloat position[] = { 10.0,10.0,0.0,1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
setProjection();
setLight();
}
void draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glutSolidTeapot(1);
glFlush();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
init();
draw();
}
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP)
camera.PitchCamera(camera.angle);
if (key == GLUT_KEY_DOWN)
camera.PitchCamera(-camera.angle);
if (key == GLUT_KEY_LEFT)
camera.YawCamera(-camera.angle);
if (key == GLUT_KEY_RIGHT)
camera.YawCamera(camera.angle);
glutPostRedisplay();
}
void KeyboardKeys(unsigned char key, int x, int y)
{
if (key == 'w')
camera.WalkStraight(camera.speed);
if (key == 's')
camera.WalkStraight(-camera.speed);
if (key == 'a')
camera.WalkTransverse(camera.speed);
if (key == 'd')
camera.WalkTransverse(-camera.speed);
glutPostRedisplay();
}
void main()
{
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(640, 480);
glutCreateWindow("Teapot");
glutDisplayFunc(display);
glutSpecialFunc(SpecialKeys);
glutKeyboardFunc(KeyboardKeys);
glutMainLoop();
}
實(shí)現(xiàn)效果
【畫質(zhì)感人】

