OpenGL实现场景漫游(Qt版)

2023-10-27

本文固定链接: 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”

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenGL实现场景漫游(Qt版) 的相关文章

  • 包含 Qt 标头的正确方法是什么?

    到目前为止我知道几种方法 includeQt 类 include
  • 如果元素 id 与搜索参数匹配,如何从 std::vector 中删除元素

    我正在尝试编写一种算法 如果项目 ID 与参数匹配 该算法将搜索项目向量并从项目向量中删除项目 请参阅下面的示例代码 struct item item int newID id newID bool operator const item
  • 稀疏向量模板类:如何清理它?

    我不确定这是否是一个好问题 如果不是 请关闭它 我开始写 使用boost coordinate vector作为起点 sparse vector有效实现类似向量接口的模板类 但很稀疏 它实现了所有常见的向量运算和一个迭代集合元素的快速稀疏迭
  • 访问结构向量

    我有一个结构 struct OutputStore int myINT string mySTRING 如果我创建一个 OutputStore 类型的数组 如下所示 OutputStore OutputFileData new Output
  • QPainterPath::arcTo 上的角度如何解释?

    我正在开发图形编辑器的功能 在其中编辑弧线 当形状是椭圆形时 QPainterPath arcTo 的行为并不像我预期的那样 当它是一个圆圈时 它会按预期工作 下面的两张图片显示了结果 在第一种情况下 我创建了一个圆 然后将其转换为初始起始
  • 如何随机打乱向量中的元素

    我正在尝试完成一项需要发生以下情况的作业 请求所需的元素数量 n 用元素 0 1 2 n 1 填充向量并将其显示到控制台 随机打乱元素并将新的排列显示到控制台 我可以输入向量 但我不知道如何对向量进行洗牌 注意 我不能使用 random s
  • Android 版 Qt 和 BoringSSL

    我正在开发一个基于 Qt 的 Android 应用程序 它使用 QSslSocket 下载数据 由于 Android 从 OpenSSL 转向 BoringSSL 因为依赖 OpenSSL 库的 Marshmallow Qt 程序在 And
  • 用矩阵变换 3D 向量的方法

    我一直在阅读一些关于用矩阵转换 Vector3 的文章 并且正在努力深入研究数学并自己编码 而不是使用现有代码 无论出于何种原因 我的学校课程从未包含矩阵 所以我正在填补我的知识空白 值得庆幸的是 我认为我只需要一些简单的东西 背景是我正在
  • QFileDialog 作为 TableView 的编辑器:如何获取结果?

    我正在使用一个QFileDialog作为某些专栏的编辑QTableView 这基本上有效 对一些焦点问题取模 请参阅here https stackoverflow com questions 22854242 qfiledialog as
  • 在 Windows 上从源代码构建 PhantomJS-2

    我正在尝试基于这些在 Windows 8 1 x64 上从源代码构建 PhantomJS 2 的开发版本指示 https github com ariya phantomjs wiki PhantomJS 2 但是我收到以下错误 mingw
  • 在信号/槽处理期间删除 QObject

    我知道从槽处理中删除 QObject 可能会使应用程序崩溃 因为它可能有其他排队的事件 因此 我将使用 obj gt deleteLater 而不是使用 delete obj 据我所知 obj 等待处理所有排队的事件 然后 删除 obj Q
  • 将类对象放置在向量中?

    我注意到我可以将一个类放置在一个向量中 这是我的程序 我收到以下错误 out blackjack exe blackjack obj blackjack obj error LNK2019 unresolved external symbo
  • Qmake 不支持源目录下的构建目录

    我创建了一个可以在 OS X 上编译和运行的应用程序 我现在想开始让它在 Windows 上运行 首先 我将项目复制到 Windows 机器上并尝试编译 但收到此错误 警告 Qmake不支持源目录下的构建目录 有任何想法吗 将影子构建目录设
  • 向量中的可变结构

    我正在尝试创建一个向量来跟踪游戏中的敌人 该向量将保存一堆可变结构 我有一个世界结构 其中有敌人作为其成员 如下所示 pub struct World pub player Creature pub enemies Vec
  • 使用信号和槽更新指针

    我对 Qt 很陌生 请帮我解决这个问题 我正在使用线程在后台执行密集操作 同时我想更新 UI 所以我使用 SIGNALS 和 SLOTS 为了更新 UI 我发出一个信号并更新 UI 让我们考虑下面的示例代码 struct sample QS
  • 如何在结构或类向量中快速搜索具有特定值的对象?由 小码哥发布于

    如果向量中有数千个结构或类对象 如何快速找到所需的对象 例如 制作游戏 我需要最快的碰撞检测方法 每个图块都是一个结构体 矢量图中有很多图块 其值是 x和y 所以基本上我这样做 For i 0 i
  • 如何阻止 Qt Creator 将可执行文件放置在“调试”子目录中?

    我正在 Qt Creator 中构建一个项目 虽然我不关心中间 obj 文件去哪里 但重要的是最终的可执行文件应放入 并运行 许多依赖项 DLL 等所在的特定目录中 被发现 因此 在 Qt Creator 中 我选择 Shadow Buil
  • 使用 OpenCV 描述符与 findFundamentalMat 匹配

    我之前发布了有关同一程序的问题 但没有收到答案 我已经纠正了当时遇到的问题 但又面临新的问题 基本上 我使用未校准的方法自动校正立体图像对的旋转和平移 我使用 SURF 等特征检测算法来查找两个图像 左右立体图像对 中的点 然后再次使用 S
  • 在 Qt 中旋转图像

    在我的应用程序中 我想旋转图像 我已将图像设置为QLabel 我已经设置了一个QPushButton 单击该按钮时我想向四个方向旋转图像 右 gt 底部 gt 左 gt 顶部 有什么帮助吗 假设您有一个指向 QLabel 的指针 您可以执行
  • std::在 std::string 和 std::vector 之间移动

    我正在与 2 个图书馆合作 一个接受并返回std strings 而其他使用std vector

随机推荐

  • 关于Findbugs的一些常见报错的翻译和处理方式

    在Lab5中要求使用 CheckStyle 和 FindBugs 工具对经过人工走查的 Lab4 代码进行自动的静态代码分析 在使用FindBugs的过程中 出现了一些难以理解的报错 经查阅资料 了解了错误的原因以及一些大致的解决办法 下面
  • Olya and Energy Drinks【Codeforces 877D】【BFS+思维+剪枝】

    Codeforces Round 442 Div 2 D 这天给学弟学妹们出了这道题 没想到背锅了 感觉要0A了 QAQ 确实 今天我再次写的时候也WA了好几发 哎 这锅背了 看到有些的代码code 访问过的点都标记为mp x y 但是这样
  • Vue常用技巧收录

    1 删除数组索引 在数组中删除一项标准做法是用 Array splice index 1 del index this arr splice index 1 Vue js2 2 0 版本中 可以直接使用Vue delete del inde
  • Scrapy爬虫框架教程(三)-- 调试(Debugging)Spiders

    摘要 前言 春节放假在老家没有网 所以最近没有更新 这周加班闲暇抽空赶紧来更新一篇 我们在写爬虫的时候经常需要修改xapth规则来获取所需的数据 而Scrapy的爬虫通常是在命令行中启动的 我们怎么去调试呢 下面我就为大家介绍两种我常用的方
  • 解决你一生的开源项目

    项目文档 https easydoc xyz s 37090916 项目演示地址 后台 https zywork cn backend Gitee地址 后台 https gitee com gz zywork zywork app pro
  • 双线性卷积神经网络模型(Bilinear CNN)

    ICCV 2015 参考资料 摘要 双线性CNN模型 包含两个特征提取器 其输出经过外积相乘 池化后获得image descriptor feature fusion的方式有很多 所以在两个数据集上进行了三种方式的feature fusio
  • SSM项目-汽车租赁后台管理系统

    使用SSM和layui做了一个汽车租赁后台管理系统 功能还没有完善 先发出来再慢慢完善更新 包结构 项目后期又用Maven整合了一下 jar包太多 把pom贴出来好了 pom xml
  • mysql中聚簇索引和主键索引

    InnoDB索引分为两种 聚簇索引 也称聚集索引 一般建表时的主键就会被mysql作为聚簇索引 如果没有主键 则选择非空唯一的索引作为聚簇索引 都没有则隐式创建一个索引作为聚簇索引 辅助索引 也称非聚簇索引或二级索引 平时我们添加的索引就是
  • 有限状态机解析HTTP请求

    一 HTTP报文 HTTP的报文格式 起始行 头部字段 空 行 消息正文 其中起始行和头部字段成为Header 消息正文称为body Header和body之间一定要有空行隔开 请求行的格式 如下 GET index html HTTP 1
  • Linux下免密登录

    Linux下免密登录 相信大家都会为登录服务器总是输入密码而困扰 那么今天我教大家免密登录 大家需要有一个服务器 一个本地linux操作系统 在这我借用同学的服务器 进入正题 ssh keygen ls a cd ssh 复制公钥 在另一个
  • QQ显示服务器繁忙2103,qq一直出现错误报告.doc

    qq一直出现错误报告 qq一直出现错误报告 QQ错误报告的解决 QQ登录出现错误报告的解决方法 现象 运行QQ时 同时弹出下面的 错误报告 窗口 关闭后QQ密码输入框没法输入密码 也就是QQ无法正常登录 错误号 CD1DD16FD6D3FC
  • 图象:sine(正弦)、cosine(余弦)与Tangent(正切)

    http www 97ae com aebiaodashi geometry trig graphs html 目录 矢量加法 距离与长度 三角函数 图象 正弦 余弦与正切 圆周函数 简谐运动 频率与振幅 波形加法与乘法 反函数 其他材料
  • SpringBoot使用@EventListener实现事件监听

    目录 1 创建监听实体类UserEvent 2 创建监听类UserEventListener 3 创建controller 发送事件 4 启动类 1 创建监听实体类UserEvent 实现ApplicationEvent类 重载构造方法加入
  • Java JNI实现调用自定义Native 方法

    JNI是Java Native Interface的缩写 通过使用 Java本地接口书写程序 可以确保代码在不同的平台上方便移植 从Java1 1开始 JNI标准成为java平台的一部分 它允许Java代码和其他语言写的代码进行交互 目录
  • 使用ELK8.4.1环境+Filebeat收集nginx日志

    文章目录 1 简介 2 下载安装 3 ElasticSerach配置 4 Logstash配置 5 Filebeat配置 6 Kabana配置 6 1 通过ElasticSerach读取日志数据 6 2 可视化显示日志数据 1 简介 ELK
  • 数据恢复软件

    数据恢复软
  • 某兮二开网钛清爽白色风资源娱乐网模板

    介绍 网钛黑白模板修改版 全网首发无任何后门 无泛滥 最近更新栏目移动到右边 左边栏目美化 顶部美化 底部修复字体不显示bug 新增超多美化代码 附赠右侧联系站长插件等等 网钛黑白模板直接覆盖即用 部分链接需要修改模板文件 网盘下载地址 h
  • org.apache.ibatis.exceptions.PersistenceException:

    org apache ibatis exceptions PersistenceException 报错如下 错误代码提示 错误信息中的关键信息 翻译 源代码如下 错误分析 解决 报错如下 错误代码提示 错误信息中的关键信息 翻译 错误分析
  • ES elasticsearch 的 索引 alias 别名的添加

    原文链接 https www elastic co guide en elasticsearch reference current indices add alias html es 的索引别名和索引名称在好多地方都是可以等价使用的 可以
  • OpenGL实现场景漫游(Qt版)

    本文固定链接 http liusir name qt learning faqs html 民警小刘 一个不错的OpenGL程序当然免不了对整个场景的漫游 在我程序中便是用W A S D来靠近 远离 向左 向右来移动场景 Q E Z C则是