OSG开发笔记(三十二):深入理解相机视口、制作支持与主视图同步变换旋转的相机HUD
若该文为原创文章,未经允许不得转载
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/143852695
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…
OSG开发专栏(点击传送门)
上一篇:《OSG开发笔记(三十一):OSG中LOD层次细节模型介绍和使用》
下一篇: 持续补充中…
前言
深入理解相机视口,摸索相机视口旋转功能,背景透明或者不透明。
本篇,实现了一个左下角旋转HUD且背景透明的相机视口。
Demo
HUD相机的坐标
抬头HUD就是通过投影矩阵来实现,具体可参看《OSG开发笔记(二十):OSG使用HUD显示文字》
- Hud要单独创建一个新相机
- 注意关闭光照,不受光照影响,所以内容以同一亮度显示
- 关闭深度测试
- 渲染顺序设置为POST,否则可能会被场景中的其他图形所覆盖。
- 设置参考贴为绝对型:setReferenceFrame(osg::Transform:ABSOLUTE_RF)
- 使其不受父节点变换的影响:setMatrix(osg::Matrix::identity())
- 投影矩阵通常会设置为屏幕尺寸大小
相机(Camera)
相机(osg::Camera)和视口(Viewport)是两个核心概念,对于理解OSG中的三维场景渲染至关重要。
相机在OSG中用于模拟真实世界中的摄影机,它负责捕捉和渲染三维场景。相机类(osg::Camera)继承自osg::Transform和osg::CullSetting类,用来管理OSG中的模型——视图矩阵。相机的管理主要是通过各种变换实现的,这些变换包括:
- 视点变换:设置视点的方向和位置。默认情况下,视点定位为坐标原点,指向Y正方向。可以通过调整视点的位置和参考点的位置来改变相机的观察方向和角度。
- 投影变换:由于显示器只能用二维图像显示三维物体,因此要靠投影来降低维数。投影变换的目的是定义一个视景体,使视景体外多余的部分被裁减掉,最终进入图像的只是视景体内的有关部分。OSG支持两种投影方式:透视投影(Perspective Projection)和正视投影(Orthographic Projection)。透视投影能够模拟人眼的视觉效果,使远处的物体看起来更小,而正视投影则保持物体的大小不变,不受距离影响。
- 视口变换:将视景体内投影的物体显示在二维的视口平面上。即将经过几何变换、投影变换和裁剪变换后的物体显示于屏幕窗口内指定的区域内,这个区域通常为矩形,称为视口。
视口(ViewPort)
具体来说,视口变换涉及以下几个参数:
- 屏幕左下角的坐标:定义了视口在屏幕上的左下角位置。
- 屏幕宽度和高度:定义了视口的宽度和高度,即相机捕捉的场景在屏幕上显示的区域大小。
在OSG中,可以通过调用相机的setViewport方法来设置视口。例如:
pCamera->setViewport(new osg::Viewport(0, 0, width, height));
这行代码创建了一个新的视口,并将其设置为相机的当前视口。其中,0和0是屏幕左下角的坐标,width和height是视口的宽度和高度。
相机与视口的关系
相机和视口在OSG中紧密相连,共同决定了三维场景的渲染效果。相机负责捕捉和渲染场景,而视口则定义了相机捕捉的场景在屏幕上的显示位置和大小。通过调整相机的各种变换和设置视口的大小和位置,可以实现丰富的三维视觉效果和交互体验。
设置相机观察函数
void setViewMatrixAsLookAt(const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up);
- eye:表示相机的位置。这是一个三维向量,指定了相机在世界坐标系中的位置。
- center:表示相机观察的中心点。这也是一个三维向量,指定了相机应该对准的物体或场景的中心位置。
- up:表示哪个方向是正方向。这同样是一个三维向量,通常用于指定相机的上方方向(例如,通常设置为 (0,0,1) 表示Y轴正方向为上方)。
设置相机位置和方向:通过指定 eye、center 和 up 三个参数,你可以精确地控制相机的位置和姿态。eye 和 center 之间的向量表示相机的观察方向,而 up 向量则用于确定相机的上方方向。
关闭漫游器:在使用 setViewMatrixAsLookAt 函数之前,通常需要关闭相机的漫游器(Camera Manipulator)。这是因为漫游器会自动更新相机的观察矩阵,从而覆盖你通过 setViewMatrixAsLookAt 设置的参数。可以通过调用 viewer->setCameraManipulator(NULL) 来关闭漫游器。
坐标系:OSG 使用右手坐标系,其中 X 轴向右,Y 轴向上,Z 轴向前。因此,在设置 eye、center 和 up 参数时,需要确保它们符合右手坐标系的规则。
视图矩阵:setViewMatrixAsLookAt 函数实际上是通过设置相机的视图矩阵来实现相机位置和姿态的调整。视图矩阵是一个 4x4 的矩阵,用于将相机坐标系中的点转换到世界坐标系中。
setViewMatrixAsLookAt 是一个强大的函数,它允许你以直观的方式设置相机的位置和姿态。通过合理地使用这个函数,你可以创建出各种复杂而逼真的三维场景和视觉效果。
Demo关键源码
创建Hud相机
// 步骤一:创建HUD摄像机
// osg::ref_ptr<osg::Camera> pCamera = new osg::Camera;osg::ref_ptr<HudRotateCamera> pCamera = new HudRotateCamera;pCamera->setMasterCamera(_pViewer->getCamera());// 步骤二:设置投影矩阵
// pCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1280, 0, 800));// 步骤三:设置视图矩阵,同时确保不被场景中其他图形位置变换影响, 使用绝对帧引用pCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);pCamera->setViewMatrix(osg::Matrix::identity());// 步骤四:清除深度缓存pCamera->setClearMask(GL_DEPTH_BUFFER_BIT);// 步骤五:设置POST渲染顺序(最后渲染)
// pCamera->setRenderOrder(osg::Camera::PRE_RENDER); // 渲染不显示
// pCamera->setRenderOrder(osg::Camera::NESTED_RENDER);pCamera->setRenderOrder(osg::Camera::POST_RENDER);// 步骤六:设置为不接收事件,始终得不到焦点pCamera->setAllowEventFocus(false);// osg::ref_ptr<osg::Geode> pGeode = new osg::Geode();
// pGeode = new osg::Geode();osg::ref_ptr<osg::StateSet> pStateSet = pGeode->getOrCreateStateSet();// 步骤七:关闭光照pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);// 步骤九:关闭深度测试pStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);// pGeode->addDrawable(pGeometry.get());pCamera->addChild(pGeode.get());pGroup->addChild(pCamera.get());
HudRotateCamera.h
#ifndef HUDROTATECAMERA_H
#define HUDROTATECAMERA_H#include "osg/Camera"
#include "osg/CopyOp"class HudRotateCamera : public osg::Camera
{
public:HudRotateCamera();HudRotateCamera(const HudRotateCamera& copy, const osg::CopyOp ©Op = osg::CopyOp::SHALLOW_COPY);META_Node(osg, HudRotateCamera);public:void setMasterCamera(Camera* camera);public:virtual void traverse(osg::NodeVisitor& nodeVisitor);protected:virtual ~HudRotateCamera();protected:osg::observer_ptr<Camera> _pMasterCamera; // 新增了相机,主要是用来获取举证的
};#endif // HUDROTATECAMERA_H
HudRotateCamera.cpp
#include "HudRotateCamera.h"HudRotateCamera::HudRotateCamera(): Camera()
{}HudRotateCamera::HudRotateCamera(const HudRotateCamera & copy, const osg::CopyOp & copyOp): Camera(copy, copyOp),_pMasterCamera(copy._pMasterCamera)
{}HudRotateCamera::~HudRotateCamera()
{}void HudRotateCamera::setMasterCamera(osg::Camera *camera)
{_pMasterCamera = camera;
}void HudRotateCamera::traverse(osg::NodeVisitor &nodeVisitor)
{double fovy, aspectRatio, vNear, vFar;_pMasterCamera->getProjectionMatrixAsPerspective(fovy, aspectRatio, vNear, vFar);// 设置投影矩阵,使缩放不起效果, 改为正投影,正投影不会随相机的拉近拉远而放大、缩小,这样就没有缩放效果,// 放大缩小是根据左右,上下距离,越大就物体越小,越小就物体越大this->setProjectionMatrixAsOrtho(-50 * aspectRatio,50 * aspectRatio,-50,50,vNear,vFar);// 让坐标轴模型位于窗体左下角osg::Vec3 vec3(-40, -40, 0);if (_pMasterCamera.valid()){// 改变视图矩阵, 让移动位置固定osg::Matrix matrix = _pMasterCamera->getViewMatrix();// 让移动固定, 即始终位于窗体右下角,否则鼠标左键按住模型可以拖动或按空格键时模型会动matrix.setTrans(vec3);this->setViewMatrix(matrix);}osg::Camera::traverse(nodeVisitor);
}
工程模板v1.35.0
入坑
入坑一:没有按照预期的方式全屏显示在正中间
问题
想一直显示在中间,且能旋转,移动中心,但是实际效果如下,方格100x100,间距1.0,测试:
尝试
将面方格缩小为10x10,线放小,测试:
缩小正交投影:
可能跟相机查看位置有关,新增相机位置和方向等信息:
没什么影响:
这里可能理解有问题,我们需要区域投影到视口,那么一个是投影的区域三维区域的大小,一个是投影到桌面2D他的大小,这里其实类似于HUD,通过HUD的方式,添加了几行代码设置投影矩阵:
经过测试,可以跳过相机调整视口、中心改变后也会移动,所以他一种在其位置区域。
然后回到前面,发现也可以,再次摸索,发现如下特点:
所以此时,纵横都是10,所以窗口大小要是符合1:1(10:10=1:1)的比例,改为400,400测试,还是一样:
但是调整为800x800就好了:
放最大也不会截取少了:
所以这个有点搞不明白了,总之是解决了,且投影矩阵和正交矩阵都可以解决,测试投影矩阵和正交举证都收视口大小影响,但是影响具体不知,就好像800x800是最小一样(其他的没测了,只测了400x400、600x600不行,看比例800x800是最小正好满窗口了)。
又怀疑投过去的区域小了,将区域放大,其位置反倒缩小,所以跟理解不一样:
- 一种是理解直接投射过去,投射过去区域变大所以变大(不是的);
- 一种是投射过去区域不变,那么区域变大视图区域可见空间范围变大(实际是这样,但是视口对屏幕的大小未变);
综合以上,又测试了加大视口,也正常,所以怀疑有可能是qt和osg结合的时候这个地方设置了一个最小值,而可能吧,欢迎探讨,这里深究暂时也没结果,且解决了,所以不继续深究了。
解决
修改相机视口大小为最小800x800。
后续补充
后续查看做的这个qtosg兼容类,做的时候,自己设置的800x800,就是这个原因了:
入坑二:相机视口区域不透明
问题
当作最前面的文本hud,是可以透明,但是这里进行调整之后,无法透明。
尝试
修改了语句,可以透明了部分,但是没了。
解决
相机是一个投影矩阵,没有透明,但是文字hud为什么透明呢?。
入坑三:内置几何体关闭光照后纯白色
问题
关闭光照后,几何体白色
原理
光照关闭要设置颜色,不想设置颜色,就单独给体开放关照。
解决
入坑四:文本看不到
问题
文本看不到,旋转后发现是太大了。
位置较大。
尝试
测试下是把整个坐标区域的展示范围扩大,那么实际看起来就是缩小。
解决
入坑五:hud旋转中心不对
问题
Hud旋转中心不对
这时旋转中心还不对,可能需要调整旋转中心
原理
开始去修改矩阵,发现都不对,其实中间点一直是0,0,0,其就是中心,那么我们设置文本的显示点不是从0,0开始即可。
下面将四边形的角点改为0,0,0来标识,然后修改文本的中心点:
解决
入坑六:hud旋转反向了
问题
旋转是反的,然后光照也反了,变换矩阵有问题
原理
数据几何变换算来算去很费劲,直接测试的结论:
代码写反了,让上下反向了,应该是-50~50
解决
还剩下光照问题,这个不好咋弄了,反正是关闭光照,或者是自己手动添加光源,用系统的可能有点问题。
这个暂时没解决,实际使用就是用一个,可以从长度单独给这个相机设置一个光源,这里因为需求本身不需要投影,不做测试了。
上一篇:《OSG开发笔记(三十一):OSG中LOD层次细节模型介绍和使用》
下一篇: 持续补充中…
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/143852695
相关文章:

OSG开发笔记(三十二):深入理解相机视口、制作支持与主视图同步变换旋转的相机HUD
若该文为原创文章,未经允许不得转载 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/143852695 各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究 长沙红胖子Qt…...

2024RISC-V中国峰会 演讲幻灯片和视频回放均已公开
目录 一、幻灯片地址: 二、演讲视频: 一、幻灯片地址: RVSC2024/slides at main cnrv/RVSC2024 GitHub 二、演讲视频: RISC-V国际基金会的个人空间-RISC-V国际基金会个人主页-哔哩哔哩视频...

河道无人机雷达测流监测系统由哪几部分组成?
在现代水利管理中,河道无人机雷达监测系统正逐渐成为一种重要的工具,为河道的安全和管理提供了强大的技术支持。那么,这个先进的监测系统究竟由哪几部分组成呢? 河道无人机雷达监测系统工作原理 雷达传感器通过发射电磁波或激光束…...

28.<Spring博客系统⑤(部署的整个过程(CentOS))>
引入依赖 Spring-boot-maven-plugin 用maven进行打包的时候必须用到这个插件。看看自己pom.xml中有没有这个插件 并且看看配置正确不正常。 注:我们这个项目打的jar包在30MB左右。 <plugin><groupId>org.springframework.boot</groupId><artif…...

OpenAI震撼发布:桌面版ChatGPT,Windows macOS双平台AI编程体验!
【雪球导读】 「OpenAI推出ChatGPT桌面端」 OpenAI重磅推出ChatGPT桌面端,全面支持Windows和macOS系统!这款新工具为用户在日常生活和工作中提供了前所未有的无缝交互体验。对于那些依赖桌面端进行开发工作的专业人士来说,这一更新带来了令人…...
香港站群服务器有助于提升网站在搜索引擎中的排名
拥有253个IP的服务器通常被称为多IP站群服务器。这种服务器架构主要用于集中管理多个网站,允许网站管理员通过一个后台管理系统来高效管理和更新这些网站。 一、主要特点 集中管理:多IP站群服务器通过统一的后台管理系统,可以实现对多个网站…...

YOLOX:使用自己数据集训练模型及改进--1.YOLOX环境搭建及运行
YOLOX环境搭建及运行 YOLO X网络架构是继YOLO v5后,由旷视科技于2021年提出的新一代anthor-free模型,研究者将网络分为输入端、Backbone、PAFPN及Predication,并在Predication提出Decoupled Head、Anchor-free和Multi positives(后文会详细介绍)。 本篇文章介绍如何通过官…...

PyTorch使用教程-深度学习框架
PyTorch使用教程-深度学习框架 1. PyTorch简介 1.1-什么是PyTorch PyTorch是一个广泛使用的开源机器学习框架,特别适合深度学习的应用。它以其动态计算图而闻名,允许在运行时修改模型,使得实验和调试更加灵活。PyTorch提供了强大的GPU加…...

TON商城与Telegram App:生态融合与去中心化未来的精彩碰撞
随着区块链技术的快速发展,去中心化应用(DApp)逐渐成为了数字生态的重要组成部分。而Telegram作为全球领先的即时通讯应用,不仅仅满足于传统的社交功能,更在区块链领域大胆探索,推出了基于其去中心化网络的…...

“乐鑫组件注册表”简介
当启动一个新的开发项目时,开发者们通常会利用库和驱动程序等现有的代码资源。这种做法不仅节省时间,还简化了项目的维护工作。本文将深入探讨乐鑫组件注册表的概念及其核心理念,旨在指导您高效地使用和贡献组件。 概念解析 ESP-IDF 的架构…...

凹凸/高度贴图、法线贴图、视差贴图、置换贴图异同
参考: 凹凸贴图、法线贴图、置换贴图-CSDN博客 视差贴图 - LearnOpenGL CN 1,Learn about Parallax(视差贴图) - 知乎 “视差贴图”的工作流程及原理(OpenGL) - 哔哩哔哩 法线与置换贴图原理讲解以及烘焙制作! - 知乎 1. Bump Mapping 凹凸贴图 BumpMap…...

ZSTD 内存泄漏问题
优质博文:IT-BLOG-CN Zstandard(简称zstd)是一种无损压缩算法,由Facebook开发并开源。它旨在提供高压缩比和高解压速度的平衡,适用于多种数据压缩需求。 特点 【1】高压缩比: zstd能够在保持较高压缩比的…...
c# npoi操作excel
今天在弄使用npoi对excel表的操作,遇到个问题就是使用workbook通过filestream打开后,让后workbook.write(filestream)居然报文件流关闭了,无法写入,弄了好久都不行,最后通过写2个excel文件来解决,现在看来我…...
十二:HTTP错误响应码:理解与应对
在现代网络技术中,HTTP(超文本传输协议)是浏览器与服务器之间沟通的基础。每当我们访问网站或发送请求,HTTP会返回一个响应码,这些代码不仅可以表示成功,还可以指示各种问题。本文将以HTTP错误响应码为主题,探讨其含义、常见类型及应对措施。 1. 400 Bad Request - 请求…...
Rust学习(六):函数式编程
Rust学习(六):函数式编程 我们在前一篇博客中已经介绍了如何通过trait和impl实现Rust的面向对象编程,但是Rust本身实际上并不提倡通过类来解决问题。Rust推崇的是函数式编程,强调将函数作为参数值或者其他函数的返回值…...

使用 Vue 和 Create-Vue 构建工程化前端项目
目录 前言1. 工程化的意义与 Vue 的生态支持2. 搭建 Vue 工程化项目2.1 环境准备2.2 使用 create-vue 创建项目2.2.1 初始化项目2.2.2 安装依赖2.2.3 本地运行 3. Vue 项目的目录结构解析4. Vue 开发流程详解4.1 项目入口与根组件4.1.1 main.js 的作用4.1.2 App.vue 的结构 4.2…...
opencv图片明暗度判断方法
OpenCV 的LAB 颜色空间(也称为 CIELAB)是一种颜色对手的颜色模型,它旨在模仿人类的色彩感知。LAB 颜色空间由三个分量组成: L: 亮度分量 (Lightness),范围从 0(黑色)到 100(白色&…...

QT6学习第三天
QT6学习第三天 第一个Widgets项目创建项目项目界面简单介绍编译文件介绍 我在第一天中将重点标了颜色,后边我把一些简单的东西都不写了,写了的都是实际用的东西,就不标颜色了。 第一个Widgets项目 首先我们创建一个widgets项目,…...

计算机网络-MSTP基础实验一(单域多实例)
前面我们已经大致了解了MSTP的基本概念和工作原理,但是我自己也觉得MSTP的理论很复杂不结合实验是很难搞懂的,今天来做一个配套的小实验以及一些配置命令。 一、网络拓扑 单域多实例拓扑 基本需求:SW1为VLAN10的网关,SW2为VLAN20的…...
React合成事件及其核心思想详解
相关联Javascript知识 1.JavaScript 的事件流 事件流是 JavaScript 处理事件的机制,它描述了事件从发生到被处理的过程。事件流主要包括两个阶段:捕获阶段和冒泡阶段。在捕获阶段,事件从文档的根元素开始,逐层向下传播到目标元素&…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...