OSG开发笔记(三十三):同时观察物体不同角度的多视图从相机技术
前言
前面的相机hud可以单独显示图形,继续深入研究相机hud,技术就是子视图了,实现该功能的直接技术是从相机技术。
本篇描述osg从相机技术
Demo


相机视口的关键调用
是否清除颜色深度缓存(清除)
pCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
如果不清除颜色缓存,渲染的窗口中若无内容,则将其他窗口渲染的内容显示到当前窗口。
设置渲染顺序(最后渲染)
// 设置POST渲染顺序(最后渲染)
pCamera->setRenderOrder(osg::Camera::POST_RENDER);
后渲染的优先级比较高(最后显示,显示优先级最高)。
设置是否接受事件(不接受)
// 设置为不接收事件,始终得不到焦点
pCamera->setAllowEventFocus(false);
设置视口大小
// 视口就是引擎三维的区域,但是注意区别于屏幕的坐标系(屏幕是左上为0,0,而三维引擎是左下为0,0)
pSlaveFrontCamera->setViewport(0,
0,
rect().width() / 4,
rect().height() / 4);
设置从相机故过程
步骤一:新建相机
osg::ref_ptr<osg::Camera> pSlaveFrontCamera = new osg::Camera;
步骤二:设置上下文
pSlaveFrontCamera->setGraphicsContext(_pViewer->getWindow());
步骤三:设置视图区域
// 视口就是引擎三维的区域,但是注意区别于屏幕的坐标系(屏幕是左上为0,0,而三维引擎是左下为0,0)
pSlaveFrontCamera->setViewport(0,
0,
rect().width() / 4,
rect().height() / 4);
步骤四:设置渲染顺序
pSlaveFrontCamera->setRenderOrder(osg::Camera::POST_RENDER);
步骤五:关键步骤添加从相机
第二个参数是缩放矩阵,第三个参数是旋转矩阵
_pViewer->addSlave(pSlaveFrontCamera,
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(0.0), 0.0, 0.0, 0.0),
true);
Demo关键源码
osg::ref_ptr<osg::Node> OsgWidget::getMulViewCameraNode()
{
// 隐藏整个demo全局的按钮面板(没用到按键的直接隐藏,不影响此Demo)
{
ui->groupBox_pannel->setVisible(false);
ui->label_cursor->setVisible(false);
ui->label_cursor_2->setVisible(false);
ui->label_msg->setVisible(false);
ui->label_state->setVisible(false);
}
osg::ref_ptr<osg::Group> pGroup = new osg::Group;
// 绘制盒体(立方体、长方体)
{
osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
// 创建专门指明精细度的类osg::TessellationHints,并设置对应精细度
osg::ref_ptr<osg::TessellationHints> pHints = new osg::TessellationHints;
pHints->setDetailRatio(0.5);
// 绘制几何类型(几何体)
qreal width = 5.0f;
// 函数1
pGeode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), width), pHints));
#if 1
// 设置关闭光照:OFF,同时旋转都能看到了(光照关闭,法向量不起作用)
{
osg::StateSet *pStateSet = pGeode->getOrCreateStateSet();
pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
// pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
}
#endif
pGroup->addChild(pGeode);
}
// 创建多视口相机
{
#if 0
// 这里改用了自己窗口已经创建的,这块废掉了,但是保留,基本的核心思想是一样的
osg::ref_ptr<osg::GraphicsContext::WindowingSystemInterface> pWindowingSystemInterface
= osg::GraphicsContext::getWindowingSystemInterface();
if(!pWindowingSystemInterface.get())
{
LOG << "if(!pWindowingSystemInterface.get())";
return pGroup.get();
}
unsigned int width = 0;
unsigned int height = 0;
pWindowingSystemInterface->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0),
width,
height);
osg::ref_ptr<osg::GraphicsContext::Traits> pTraits = new osg::GraphicsContext::Traits;
{
pTraits->x = 0;
pTraits->y = 0;
pTraits->width = width;
pTraits->height = height;
pTraits->windowDecoration = false;
pTraits->doubleBuffer = true;
pTraits->sharedContext = 0;
}
LOG << pTraits->x << pTraits->y << pTraits->width << pTraits->height;
osg::ref_ptr<osg::GraphicsContext> pGraphicsContext = osg::GraphicsContext::createGraphicsContext(pTraits.get());
if(!pGraphicsContext->valid())
{
LOG << "if(!pGraphicsContext->valid())";
return pGroup.get();
}
#endif
double angle = 15.0f;
#if 1
// 前
osg::ref_ptr<osg::Camera> pSlaveFrontCamera = new osg::Camera;
pSlaveFrontCamera->setGraphicsContext(_pViewer->getWindow());
// 视口就是引擎三维的区域,但是注意区别于屏幕的坐标系(屏幕是左上为0,0,而三维引擎是左下为0,0)
pSlaveFrontCamera->setViewport(0,
0,
rect().width() / 4,
rect().height() / 4);
pSlaveFrontCamera->setRenderOrder(osg::Camera::POST_RENDER);
_pViewer->addSlave(pSlaveFrontCamera,
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(0.0), 0.0, 0.0, 0.0),
true);
#endif
#if 1
// 后
osg::ref_ptr<osg::Camera> pSlaveBehindCamera = new osg::Camera;
pSlaveBehindCamera->setGraphicsContext(_pViewer->getWindow());
// 视口就是引擎三维的区域,但是注意区别于屏幕的坐标系(屏幕是左上为0,0,而三维引擎是左下为0,0)
pSlaveBehindCamera->setViewport(0,
rect().width() / 4 * 3,
rect().width() / 4,
rect().height() / 4);
pSlaveBehindCamera->setRenderOrder(osg::Camera::POST_RENDER);
_pViewer->addSlave(pSlaveBehindCamera,
osg::Matrix::translate(0, 0, 0),
osg::Matrix::rotate(osg::DegreesToRadians(30), 1.0, 0.0, 0.0),
true);
#endif
#if 0
// 左
// osg::ref_ptr<osg::Camera> pSlaveLeftCamera = new osg::Camera;
// pSlaveLeftCamera->setGraphicsContext(_pViewer->getWindow());
osg::ref_ptr<HudRotateCamera> pSlaveLeftCamera = new HudRotateCamera;
pSlaveLeftCamera->setGraphicsContext(_pViewer->getWindow());
pSlaveLeftCamera->setMasterCamera(_pViewer->getCamera());
pSlaveLeftCamera->setViewport(0,
rect().height() / 8 * 3,
rect().width() / 4,
rect().height() / 4);
pSlaveLeftCamera->setRenderOrder(osg::Camera::POST_RENDER);
#if 0
_pViewer->addSlave(pSlaveLeftCamera,
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(angle), 0.0, 0.0, 1.0),
true);
#endif
#if 0
// 设置相机位置,观察目标点和方向
osg::Vec3f vec3Eye = osg::Vec3f(100, 100, 0);
osg::Vec3f vec3Center = osg::Vec3f(0, 0, 0);
osg::Vec3f vec3Up = osg::Vec3f(0, 1, 0);
pSlaveLeftCamera->setViewMatrixAsLookAt(vec3Eye, vec3Center, vec3Up);
_pViewer->addSlave(pSlaveLeftCamera);
#endif
#if 1
// 设置slave相机的位置和方向
osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform();
// 设置平移矩阵,根据需要进行调整
osg::Matrix matrix;
matrix.makeTranslate(0, 0, 0); // 这里的x, y, z是你想要平移到的位置
transform->setMatrix(matrix);
transform->addChild(pGroup);
_pViewer->addSlave(pSlaveLeftCamera,
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(15.0f), 0.0, 1.0, 1.0),
true);
pSlaveLeftCamera->setProjectionMatrixAsPerspective(
100.0f, 1.0, 1.0f, 100.0f);
#endif
#endif
#if 0
// 右
osg::ref_ptr<osg::Camera> pSlaveRightCamera = new osg::Camera;
pSlaveRightCamera->setGraphicsContext(_pViewer->getWindow());
pSlaveRightCamera->setViewport(rect().width() / 4 * 3,
rect().height() / 8 * 3,
rect().width() / 4,
rect().height() / 4);
pSlaveRightCamera->setRenderOrder(osg::Camera::POST_RENDER);
_pViewer->addSlave(pSlaveRightCamera,
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(-angle), 0.0, 0.0, 1.0),
true);
#endif
#if 0
// 上
osg::ref_ptr<osg::Camera> pSlaveUpCamera = new osg::Camera;
pSlaveUpCamera->setGraphicsContext(_pViewer->getWindow());
pSlaveUpCamera->setViewport(rect().width() / 8 * 3,
0,
rect().width() / 4,
rect().height() / 4);
pSlaveUpCamera->setRenderOrder(osg::Camera::POST_RENDER);
_pViewer->addSlave(pSlaveUpCamera,
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(angle), 1.0, 0.0, 0.0),
true);
#endif
#if 0
// 下
osg::ref_ptr<osg::Camera> pSlaveDownCamera = new osg::Camera;
pSlaveDownCamera->setGraphicsContext(_pViewer->getWindow());
pSlaveDownCamera->setViewport(rect().height() / 8 * 3,
rect().height() / 8 * 6,
rect().width() / 4,
rect().height() / 4);
pSlaveDownCamera->setRenderOrder(osg::Camera::POST_RENDER);
_pViewer->addSlave(pSlaveDownCamera,
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(-angle), 1.0, 0.0, 0.0),
true);
#endif
}
return pGroup.get();
}
工程模板v1.36.0

入坑
入坑一:设置相机就崩溃
问题

解决过程
定位到不设置相机就不崩溃,然后这里是笔者自己造的Qt与OSG结合的,使用了位置,这里也可以查看实际打印的创建的区域坐标和大小,确实也是不对:

那直接把场景里面的gc赋值给他测试,是可以的,修改的地方有点多,因为这个Qt+OSG是笔者根据源码原理进行调整渲染的,与直接编译出来的qt+osg还是有点区别,总之一句话,就是Qt渲染窗口里面已经有这个osg::ref_ptrosg::GraphicsContext了,不用去额外建立了:
删除以下代码:

然后再调整相机代码,还有从Qt渲染窗口里面增加拿到这个内容上下文的函数就好了。
解决
新增获取函数,原本不能获取


这里实际大小为:

所以外面代码,直接用窗口的宽高好了(笔者是铺满的):这里是要缩小放前面,那就是改为4/1吧:


入坑二:左视图没有
问题
左视图应该显示,但是没显示

解决过程
改成一样的:

然后不偏移试试:

偏移一个小角度试试:

所以是Y轴的中心不对,但是我们也没有改,测试绕x轴:

然后绕z轴,发现就z轴没有偏移:



尝试单独设置添加相机的视口是无效的:


尝试单独修改同步旋转的相机去修改视口,也是无效:

继续尝试:

是否与内置相机的视口有关系,测试也无关:


解决(主技术方向未解决)
从原始从相机技术方面暂时没有解决,因为也尝试了更改矩阵、修改相机视角观看位置都没什么变化。
可以确认的是,应该是相机旋转的中心不对,并不是场景中心不对,所以鼠标拽托中间还是在旋转,而视角旋转则x和y轴存在偏移。X和y存在偏移就是左右和里外,若是与屏幕有关也是上下和左右,所以这里这么分析推断也不对。
代码全部放出,读者有兴趣可以提供协助,一起探讨。
规避解决方法
直接在相机中修改偏移旋转,然后当作结点加入,是可以解决,而且还不能是从相机,需要addChild进入:

这时候拉伸有问题:

变形了:


终于外挂一个东西解决:


但是鼠标中键按下偏移中心点,会都向右,理论上反向180°的y轴应该向左,但是还是向右,因为是场景偏移,我们规避是对场景下的相机进行旋转,所以实际是移动场景相机了,相机里面的正反对外无效。
官方从相机示例(也存在问题,怀疑是osg3.4.0源码bug)
为了再次深入论证是否代码问题,笔者又用官方的demo实现:
#include <osg/Camera>
#include <osg/Group>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osgViewer/Viewer>
#include <osg/GraphicsContext>
int main(int argc, char *argv[])
{
osg::ref_ptr<osg::Group> pGroup = new osg::Group;
// 绘制盒体(立方体、长方体)
{
osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
// 创建专门指明精细度的类osg::TessellationHints,并设置对应精细度
osg::ref_ptr<osg::TessellationHints> pHints = new osg::TessellationHints;
pHints->setDetailRatio(0.5);
// 绘制几何类型(几何体)
double width = 5.0f;
// 函数1
pGeode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), width), pHints));
// 设置关闭光照:OFF,同时旋转都能看到了(光照关闭,法向量不起作用)
{
osg::StateSet *pStateSet = pGeode->getOrCreateStateSet();
pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
}
pGroup->addChild(pGeode);
}
osg::GraphicsContext::WindowingSystemInterface * wsi = osg::GraphicsContext::getWindowingSystemInterface();
if(!wsi)
{
return 0;
}
osg::ref_ptr<osg::GraphicsContext::Traits > traits = new osg::GraphicsContext::Traits;
traits->x = 0;
traits->y = 0;
traits->width = 800;
traits->height = 600;
traits->windowDecoration = false;
traits->doubleBuffer = true;
traits->sharedContext = 0;
osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits);
if(!gc.valid())
{
return 0;
}
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
osg::ref_ptr<osg::Camera> master = new osg::Camera;
master->setGraphicsContext(gc);
master->setViewport(0, 0, 800, 600);
viewer->addSlave(master.get());
osg::ref_ptr<osg::Camera> leftcam = new osg::Camera;
leftcam->setGraphicsContext(gc);
leftcam->setViewport(0, 0, 800 / 2, 600 / 2);
leftcam->setRenderOrder(osg::Camera::POST_RENDER);
viewer->addSlave(leftcam.get(),
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(15.0), 0.0, 1.0, 0.0),
true);
viewer->setSceneData(pGroup);
viewer->run();
return 0;
}

改进后相机代码:
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
osg::ref_ptr<osg::Camera> master = new osg::Camera;
master->setGraphicsContext(gc);
master->setViewport(0, 0, 800, 800);
viewer->addSlave(master.get());
{
osg::ref_ptr<osg::Camera> leftcam = new osg::Camera;
leftcam->setGraphicsContext(gc);
leftcam->setViewport(0, 0, 100, 100);
leftcam->setRenderOrder(osg::Camera::POST_RENDER);
viewer->addSlave(leftcam.get(),
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(15.0), 1.0, 0.0, 0.0),
true);
}
{
osg::ref_ptr<osg::Camera> leftcam = new osg::Camera;
leftcam->setGraphicsContext(gc);
leftcam->setViewport(100, 0, 100, 100);
leftcam->setRenderOrder(osg::Camera::POST_RENDER);
viewer->addSlave(leftcam.get(),
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(15.0), 0.0, 1.0, 0.0),
true);
}
{
osg::ref_ptr<osg::Camera> leftcam = new osg::Camera;
leftcam->setGraphicsContext(gc);
leftcam->setViewport(200, 0, 100, 100);
leftcam->setRenderOrder(osg::Camera::POST_RENDER);
viewer->addSlave(leftcam.get(),
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(15.0), 0.0, 0.0, 1.0),
true);
}
{
osg::ref_ptr<osg::Camera> leftcam = new osg::Camera;
leftcam->setGraphicsContext(gc);
leftcam->setViewport(300, 0, 100, 100);
leftcam->setRenderOrder(osg::Camera::POST_RENDER);
viewer->addSlave(leftcam.get(),
osg::Matrix(),
osg::Matrix::rotate(osg::DegreesToRadians(180.0), 0.0, 0.0, 1.0),
true);
}
所以是osg3.4.0的源码这块就有问题:

OSG开发笔记(三十三):同时观察物体不同角度的多视图从相机技术的更多相关文章
- Django开发笔记三
Django开发笔记一 Django开发笔记二 Django开发笔记三 Django开发笔记四 Django开发笔记五 Django开发笔记六 1.基于类的方式重写登录:views.py: from ...
- Django笔记三十三之缓存操作
本文首发于公众号:Hunter后端 原文链接:Django笔记三十三之缓存操作 这一节介绍一下如何在 Django 中使用 redis 做缓存操作. 在 Django 中可以有很多种方式做缓存,比如数 ...
- Java开发笔记(十三)利用关系运算符比较大小
前面在<Java开发笔记(九)赋值运算符及其演化>中提到,Java编程中的等号“=”表示赋值操作,并非数学上的等式涵义.Java通过等式符号“==”表示左右两边相等,对应数学的等号“=”: ...
- .net开发笔记(十三) Winform常用开发模式第一篇
上一篇博客最后我提到“异步编程模型”(APM),之后本来打算整理一下这方面的材料然后总结一下写篇文章与诸位分享,后来在整理的过程中不断的延伸不断地扩展,发现完全偏离了“异步编程”这个概念,前前后后所有 ...
- BizTalk开发系列(三十三)BizTalk之Excel终极解决方案
Excel作为优秀的客户端数据处理程序得到了广泛的应用. 由于其简单又强大的功能在很多公司或个人的数据处理中占用非常重要的位置. 而BizTalk作为微软的SOA主打产品虽然免费提供了很多Adapte ...
- Android UI开发第三十三篇——Navigation Drawer For Android API 7
Creating a Navigation Drawer中使用的Navigation Drawer的android:minSdkVersion="14",现在Android API ...
- 安卓开发笔记(十三):SQLite数据库储存(下)数据的增添,更改,删除,查询
SQLite数据库存储(下) 1.增添数据 对于添加数据的话我们只需要在主活动当中import新的包以及在主活动当中写上适当的代码就可以了,不需要在我们之前创建新的类当中书写新的代码.现在的主活动 ...
- Android笔记三十三.BroadcastReceiver使用
广播是一种广泛运用在应用程序之间传输信息的机制,而BroadcastReceiver是对发送出来的广播进行过滤接收并响应的一类组件. BroadcastReceiver本质上是一种全局监听器. ...
- Java开发学习(三十三)----Maven私服(一)私服简介安装与私服分类
一.私服简介 团队开发现状分析 (1)张三负责ssm_crm的开发,自己写了一个ssm_pojo模块,要想使用直接将ssm_pojo安装到本地仓库即可 (2)李四负责ssm_order的开发,需要用到 ...
- RBL开发笔记三
2014-08-26 20:06:24 今天就是在开发这个EPOLL来处理网络事件 封装较为健壮的EPOLL模型来处理基本的网络IO 1) 超时这个主题先没有弄 在开发EPOLL包括select/po ...
随机推荐
- WPF 如何利用Blend给Button添加波纹效果
先看一下效果吧: 如果不会写动画或者懒得写动画,就直接交给Blend来做吧; 其实Blend操作起来很简单,有点类似于在操作PS,我们只需要设置关键帧,鼠标点来点去就可以了,Blend会自动帮我们生成 ...
- DASCTF 2024暑期挑战赛 RE
DASCTF 2024暑期挑战赛 DosSnake 使用ghidra看反汇编 发现有XOR操作 在ida里面看汇编跟一下 字符DASCTF地址往下6个存放的数据与DASCTF字符串进行异或 A=[0x ...
- Android Adapter中组件EditText文本变化监听 addTextChangedListener
问题背景:使用适配器显示一个列表,列表中Item中有EditText,滚动时会有EditText组件内容消失 步骤: 1. 在Adapter中,添加interface public interface ...
- Innodb对表加锁的过程分析
本节我们通过一些具体的案例来分析Innodb对表上锁的过程.具体场景如下图所示. 在这里我们将语句分为4类:普通select(快照读).锁定读.半一致性读 和 insert语句. 普通读 普通的sel ...
- 五分钟入门Webworker
Webworker是基于HTML5提出的一种技术,允许主线程创建Worker线程,将一些任务分配给Worker运行,主线程运行同时,Worker线程在后台运行,互不干扰.等Worker线程完成计算任务 ...
- asp.net core 2使用本地https证书
先在PowerShell里运行以下, 生成证书: # setup certificate properties including the commonName (DNSName) property ...
- 参与 2023 第二季度官方 Flutter 开发者调查
Flutter 3.10 已经正式发布,每个季度一次的 Flutter 开发者调查也来啦!邀请社区的各位成员们填写: 调研旨在了解你对 Flutter 的满意程度以及对其各个子系统的反馈.你的意见将对 ...
- python3 numpy的一些小知识点
简介 一个用python实现的科学计算,包括: 1.一个强大的N维数组对象Array: 2.比较成熟的(广播)函数库: 3.用于整合C/C++和Fortran代码的工具包: 4.实用的线性代数.傅里叶 ...
- SuperMap iManager for K8S 删除旧环境修改NFS地址流程
一.完整删除SuperMap iManager 找到SuperMap iManager安装目录,执行: ./shutdown.sh -v 二.修改NFS存储路径 有两种办法,一种是直接修改/etc/e ...
- Springboot 读取 resource 目录下的Excel文件并下载
如果 inputStream 为null ,或者提示 文件路径不存在,执行 mvn clean 并 重启项目,查看target 目录下是否存在该文件 @GetMapping("/downlo ...