OpenGL实现场景漫游(Qt版)

本文固定链接: http://liusir.name/qt-learning-faqs.html | 民警小刘

 

 一个不错的OpenGL程序当然免不了对整个场景的漫游。在我程序中便是用W、A、S、D来靠近,远离,向左,向右来移动场景,Q、E、Z、C则是旋转场景。同时,补充一条,我用鼠标滚轮实现了物体的放大和缩小,效果上和按W、S键是相同的,但本质上是有差别的,呵呵~

  我要贴出的这个Camera类是从《OpenGL游戏编程》里提取出来的,并且已经在Qt环境下运行成功(本来代码是在VS2005)。

  Camera.h内容:

 

#ifndef __CAMERA_H__
#define __CAMERA_H__

#include "Vector.h" /* 包含向量类头文件 */

/* 摄像机类 */
class Camera
{
public:

        /* 构造函数和析构函数 */
	Camera();
	~Camera();

        /* 获得摄像机状态方法 */
	Vector3 getPosition()   {	return m_Position;		}
	Vector3 getView()	    {	return m_View;			}
	Vector3 getUpVector()   {	return m_UpVector;		}
	float   getSpeed()      {   return m_Speed;         }

        /* 设置速度 */
	void setSpeed(float speed)
	{
		m_Speed  = speed;
	}

        /* 设置摄像机的位置, 观察点和向上向量 */
	void setCamera(float positionX, float positionY, float positionZ,
			 	   float viewX,     float viewY,     float viewZ,
				   float upVectorX, float upVectorY, float upVectorZ);

        /* 旋转摄像机方向 */
	void rotateView(float angle, float X, float Y, float Z);

        /* 根据鼠标设置摄像机观察方向 */
        void setViewByMouse();

        /* 左右摄像机移动 */
	void yawCamera(float speed);

        /* 前后移动摄像机 */
	void moveCamera(float speed);

        /* 放置摄像机 */
	void setLook();

        /* 得到摄像机指针 */
	static Camera* GetCamera(void) { return m_pCamera;}

private:
        /* 摄像机属性 */
        static Camera  *m_pCamera;      /* 当前全局摄像机指针 */
        Vector3        m_Position;      /* 位置 */
        Vector3        m_View;          /* 朝向 */
        Vector3        m_UpVector;      /* 向上向量 */
        float          m_Speed;         /* 速度 */

};

#endif //__CAMERA_H__
Camera.cpp内容:
 

#include "Stdafx.h" #include "Camera.h"                    /* 包含摄像机头文件 */ #include "Vector.h"                    /* 包含向量类 */ #include "math.h"

Camera* Camera::m_pCamera = NULL;

/* 构造函数 */ Camera::Camera() {     /* 初始化向量值 */     Vector3 zero = Vector3(0.0, 0.0, 0.0);     Vector3 view = Vector3(0.0, 1.0, 0.5);     Vector3 up   = Vector3(0.0, 0.0, 1.0);

    /* 初始化摄像机 */

    //观察位置 Eye     m_Position = zero;

    //被观察点     m_View  = view;

    //倒立还是正立     m_UpVector = up;

    //前进速度     m_Speed     = 0.05f;

    //相机指针     m_pCamera = this;

}

Camera::~Camera() { }

/* 设置摄像机的位置,朝向和向上向量 */ void Camera::setCamera( float positionX, float positionY, float positionZ,                         float viewX,     float viewY,     float viewZ,                         float upVectorX, float upVectorY, float upVectorZ) {     /* 构造向量 */     Vector3 Position = Vector3(positionX, positionY, positionZ);     Vector3 View  = Vector3(viewX, viewY, viewZ);     Vector3 UpVector = Vector3(upVectorX, upVectorY, upVectorZ);

    /* 设置摄像机 */     m_Position = Position;     m_View     = View;     m_UpVector = UpVector; }

/*  旋转摄像机方向  */ void Camera::rotateView(float angle, float x, float y, float z) {     Vector3 newView;

    /* 计算方向向量 */     Vector3 view = m_View - m_Position;

    /* 计算 sin 和cos值 */     float cosTheta = (float)cos(angle);     float sinTheta = (float)sin(angle);

    /* 计算旋转向量的x值 */     newView.x  = (cosTheta + (1 - cosTheta) * x * x)  * view.x;     newView.x += ((1 - cosTheta) * x * y - z * sinTheta) * view.y;     newView.x += ((1 - cosTheta) * x * z + y * sinTheta) * view.z;

    /* 计算旋转向量的y值 */     newView.y  = ((1 - cosTheta) * x * y + z * sinTheta) * view.x;     newView.y += (cosTheta + (1 - cosTheta) * y * y)  * view.y;     newView.y += ((1 - cosTheta) * y * z - x * sinTheta) * view.z;

    /* 计算旋转向量的z值 */     newView.z  = ((1 - cosTheta) * x * z - y * sinTheta) * view.x;     newView.z += ((1 - cosTheta) * y * z + x * sinTheta) * view.y;     newView.z += (cosTheta + (1 - cosTheta) * z * z)  * view.z;

    /* 更新摄像机的方向 */     m_View = m_Position + newView; }

/* 用鼠标旋转摄像机 */ void Camera::setViewByMouse() {/*此函数已放弃。如要使用,在Update处调用即可*/

    /*< 保存当前鼠标位置 */     POINT mousePos;     int middleX = GetSystemMetrics(SM_CXSCREEN) >> 1; /*< 得到屏幕宽度的一半 */     int middleY = GetSystemMetrics(SM_CYSCREEN) >> 1; /*< 得到屏幕高度的一半 */

    float angleY = 0.0f;/*< 摄像机左右旋转角度 */     float angleZ = 0.0f;/*< 摄像机上下旋转角度 */     static float currentRotX = 0.0f;     /* 得到当前鼠标位置 */     GetCursorPos(&mousePos);     ShowCursor(TRUE);     /* 如果鼠标没有移动,则不用更新 */     if( (mousePos.x == middleX) && (mousePos.y == middleY) )         return;     /* 设置鼠标位置在屏幕中心 */     SetCursorPos(middleX, middleY);     /* 得到鼠标移动方向 */     angleY = (float)( (middleX - mousePos.x) ) / 1000.0f;     angleZ = (float)( (middleY - mousePos.y) ) / 1000.0f;     static float lastRotX = 0.0f;      /* 用于保存旋转角度 */     lastRotX = currentRotX;     /* 跟踪摄像机上下旋转角度 */     currentRotX += angleZ;     /* 如果上下旋转弧度大于1.0,我们截取到1.0并旋转 */     if(currentRotX > 1.0f)     {         currentRotX = 1.0f;

        /* 根据保存的角度旋转方向 */         if(lastRotX != 1.0f)         {             /* 通过叉积找到与旋转方向垂直的向量 */             Vector3 vAxis = m_View - m_Position;             vAxis = vAxis.crossProduct(m_UpVector);             vAxis = vAxis.normalize();

            ///旋转             rotateView( 1.0f - lastRotX, vAxis.x, vAxis.y, vAxis.z);         }     }     /* 如果旋转弧度小于-1.0,则也截取到-1.0并旋转 */     else if(currentRotX < -1.0f)     {         currentRotX = -1.0f;

        if(lastRotX != -1.0f)         {

            /* 通过叉积找到与旋转方向垂直的向量 */             Vector3 vAxis = m_View - m_Position;             vAxis = vAxis.crossProduct(m_UpVector);             vAxis = vAxis.normalize();

            ///旋转             rotateView( -1.0f - lastRotX, vAxis.x, vAxis.y, vAxis.z);         }     }     /* 否则就旋转angleZ度 */     else     {         /* 找到与旋转方向垂直向量 */         Vector3 vAxis = m_View - m_Position;         vAxis = vAxis.crossProduct(m_UpVector);         vAxis = vAxis.normalize();

        ///旋转         rotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);     }

    /* 总是左右旋转摄像机 */     rotateView(angleY, 0, 1, 0); }

/* 左右移动摄像机 */ void Camera::yawCamera(float speed) {     Vector3 yaw;     Vector3 cross = m_View - m_Position;     cross = cross.crossProduct(m_UpVector);

    ///归一化向量     yaw = cross.normalize();

    m_Position.x += yaw.x * speed;     m_Position.z += yaw.z * speed;

    m_View.x += yaw.x * speed;     m_View.z += yaw.z * speed;

}

/* 前后移动摄像机 */ void Camera::moveCamera(float speed) {     /* 计算方向向量 */     Vector3 vector = m_View - m_Position;     vector = vector.normalize();         /*< 单位化 */

    /* 更新摄像机 */     m_Position.x += vector.x * speed;    /*< 根据速度更新位置 */     m_Position.y += vector.y * speed;     m_Position.z += vector.z * speed;

    m_View.x += vector.x * speed;   /*< 根据速度更新方向 */     m_View.y += vector.y * speed;     m_View.z += vector.z * speed;

}

/* 设置视点 */ void Camera::setLook() {

    /* 设置视口 */     gluLookAt(m_Position.x, m_Position.y, m_Position.z,               m_View.x,  m_View.y,     m_View.z,               m_UpVector.x, m_UpVector.y, m_UpVector.z); }

 使用方法:

/* 设置全局相机 */ m_Camera.setLook();

/* 初始化相机 */ m_Camera.setCamera(0.0f, 0.0f, -3.0f,   //Eye                    0.0f, 0.0f, -7.0f,   //Center                    0.0f, 1.0f, 0.0f);  //Up

case Qt::Key_W://镜头靠近     m_Camera.moveCamera(m_Camera.getSpeed());     break; case Qt::Key_S://镜头远离     m_Camera.moveCamera(-m_Camera.getSpeed());

上面记得要先初始化相机,然后给其“摆放”好,然后利用键盘事件改变其视点就好了,不过对其的运用前提要理解好glLookAt函数,可以参考我之前的日志“gluPerspective与glLookAt”

 

阅读更多

没有更多推荐了,返回首页