osgGA::CameraManipulator类computeHomePosition函数分析

news2024/11/25 14:55:38

osgGA::CameraManipulator类computeHomePosition函数代码如下:

void CameraManipulator::computeHomePosition(const osg::Camera *camera, bool useBoundingBox)
{
    if (getNode())
    {
        osg::BoundingSphere boundingSphere;

        OSG_INFO<<" CameraManipulator::computeHomePosition("<<camera<<", "<<useBoundingBox<<")"<<std::endl;

        if (useBoundingBox)
        {
            // compute bounding box
            // (bounding box computes model center more precisely than bounding sphere)
            osg::ComputeBoundsVisitor cbVisitor;
            getNode()->accept(cbVisitor);
            osg::BoundingBox &bb = cbVisitor.getBoundingBox();

            if (bb.valid()) boundingSphere.expandBy(bb);
            else boundingSphere = getNode()->getBound();
        }
        else
        {
            // compute bounding sphere
            boundingSphere = getNode()->getBound();
        }

        OSG_INFO<<"    boundingSphere.center() = ("<<boundingSphere.center()<<")"<<std::endl;
        OSG_INFO<<"    boundingSphere.radius() = "<<boundingSphere.radius()<<std::endl;

        // set dist to default
        double dist = 3.5f * boundingSphere.radius();

        if (camera)
        {

            // try to compute dist from frustum
            double left,right,bottom,top,zNear,zFar;
            if (camera->getProjectionMatrixAsFrustum(left,right,bottom,top,zNear,zFar))
            {
                double vertical2 = fabs(right - left) / zNear / 2.;
                double horizontal2 = fabs(top - bottom) / zNear / 2.;
                double dim = horizontal2 < vertical2 ? horizontal2 : vertical2;
                double viewAngle = atan2(dim,1.);
                dist = boundingSphere.radius() / sin(viewAngle);
            }
            else
            {
                // try to compute dist from ortho
                if (camera->getProjectionMatrixAsOrtho(left,right,bottom,top,zNear,zFar))
                {
                    dist = fabs(zFar - zNear) / 2.;
                }
            }
        }

        // set home position
        setHomePosition(boundingSphere.center() + osg::Vec3d(0.0,-dist,0.0f),
                        boundingSphere.center(),
                        osg::Vec3d(0.0f,0.0f,1.0f),
                        _autoComputeHomePosition);
    }
}

       这个函数用于计算操控器默认位置。该计算方法考虑了相机视场角和模型大小及相机和模型之间的距离足够远,以便能将整个模型投放到计算机屏幕上。如果第1个参数即相机对象为NULL,场景到相机之间的距离将不能被计算,这种情况下将采用默认距离。useBoundingBox参数将用场景的包围盒来代替场景的包围球,因为包围盒在用于计算场景中心时将比包围球更精确,这对某些应用程序来说,有时很重要。

       这个函数中,最难理解的第39到第43行代码,下面分析:

       关于osg的坐标系统有必要解释一下:OpenGL的世界坐标轴向是:x轴向右,y轴向上,z轴向屏幕外。在osg中实际上也是一样的,只不过漫游器在设置视点时把视点设置在了y轴负方向并朝向y轴正向,导致这二者看起来坐标系统不一致。 感觉像是OpenGL坐标系统沿着x轴顺时针翻转90度。并且osg提供的模型数据的顶点坐标也都遵循这一原则,最终让使用者感觉osg的坐标系统是 x轴向右,y轴向屏幕里,z轴朝上。如下为OPenGL中提到的经典的平头截体:

 图1 平头截体

      在上图中,操控器也即相机位于O点;M2点是近面和底面交线的中点(近面和底面是垂直的);M1点是近面和上顶面交线的中点;A点是近平面左上角顶点,其坐标为(left,top);D点近平面右下角顶点,其坐标为(right, bottom);E是左下角顶点,坐标为(left, bottom);OM2 = zNear(注:图中zNear标注的不对); ∠M1OM2 = Foxy为Z轴方向(垂直方向)的视场角;∠EOD = θ是水平方向视场角。
 

 图 2

在图2中,OB线段将垂直方向的视场角等分,即2 * viewAngle = ∠M1OM2 = Foxy, 根据几何关系不难得出:        

   tan(viewAngle) = FB / BO = FB / zNear

     根据图1,FB = (top - bottom) / 2.0,则:

viewAngle = atan2( (top - bottom) / 2.0 / zNear, 1.);

同样地:

   tan( θ/ 2.0) = EM2 / zNear = (right - left) / 2.0 /zNear

所以:

θ / 2.0 = atan2( (right - left) / 2.0 / zNear, 1.);

为了防止负数,最好加上绝对值,即:

viewAngle = atan2( fab(top - bottom) / 2.0 / zNear, 1.);
θ / 2.0 = atan2( fab(right - left) / 2.0 / zNear, 1.);

      上述的fabs(right - left) / 2 / zNear 就是代码中的vertical2;而fab(top - bottom) / 2.0 / zNear就是代码中的horizontal2。代码中的取名是编写者把变量搞反了,应该是:

double horizontal2 = fabs(right - left) / zNear / 2.;
double vertical2 = fabs(top - bottom) / zNear / 2.;

 这个问题我同gitbub上osg的开发维护者robertosfield 沟通过,下面是他的回复

沟通连接为:Should naming be exchanged? · Issue #1227 · openscenegraph/OpenSceneGraph (github.com) 。

       然后再比较水平视场角和垂直视场角哪个小,以小的为场景包围球的最终视场角,这样就可以让整个场景被相机观察到,即整个场景都在平头截体内部(大角表示的视场角方向))或被平头截体内切(小角表示的视场角方向)。如果以大角为最终视场角,则当场景正好被大角所表示的平头截体内切时,则此时小的视场角(可能是水平方向的视场角,也可能是垂直方向的视场角)必定和场景包围球相交了,根据OPenGL裁剪原理,所有超出平头截体之外的场景都会被裁剪掉,从而导致部分场景不能显示在计算机屏幕上,这样用户就感觉怪怪的(我想要的场景有部分没显示在屏幕上)。

        算出角度后,根据正弦就很容易算出相机离包围球中心的距离了。最后如果获取相机透视投影参数失败,那么按平行投影进行计算。平行投影的计算比较简单,去远平面和近平面差值的1/2。

参考链接:

【1】:osg中漫游器的原理——osgGA::CameraManipulator(二)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/478229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

继续细说文件

先来了解几个函数&#xff1a; fopen&#xff0c;这个函数有2个参数分别为&#xff08;字符串也就是要记得打引号&#xff09;路径&#xff0c;和&#xff08;字符串&#xff09;操作模式&#xff0c;返回值为FILE类型的指针&#xff0c;也就是一个指向文件信息的结构的指针&a…

Java 基础入门篇(五)——— 面向对象编程

文章目录 一、面向对象的思想二、类的定义与对象的创建三、对象内存分配情况 ★ 3.1 两个对象的内存图3.2 两个变量指向同一个对象内存图 四、构造器4.1 构造器的格式与分类4.2 构造器的调用 五、 this 关键字六、封装七、标准JavaBean补充&#xff1a;局部变量和成员变量的区别…

【计算机网络详解】——物理层(学习笔记)

&#x1f4d6; 前言&#xff1a;今天我们将一起探索电脑网络中最基础的一层&#xff0c;物理层。从摩斯电码到光纤传输的高速互联网时代&#xff0c;物理层在不断发展和创新。让我们一起深入到网络通讯的本质&#xff0c;探究物理层与我们的日常联系密不可分的原因。 目录 &…

面试篇:Spring

一、Spring框架的单例bean是线程安全的吗&#xff1f; 1、Spring框架中的bean是单例的吗&#xff1f; spring框架中的bean是单例的&#xff0c;在默认情况下是singleton模式&#xff0c;即单例模式。如果需要更改则可以在Scope注解设置为prototype为多例模式。 singleton:bea…

ECharts---X轴文字显示不全

原因&#xff1a; X轴标签文字过多导致显示不全解决方法&#xff1a;(一)xAxis 中添加 xAxis.axisLabel 属性 axisLabel是用来设置x轴的刻度以及一些参数的设置&#xff1a; (1)interval设置的是间隔数&#xff0c;把x轴分成10个间隔&#xff0c;根据x轴的数据自动划分份数值…

【计算机专业漫谈】【计算机系统基础学习笔记】W1-计算机系统概述

利用空档期时间学习一下计算机系统基础&#xff0c;以前对这些知识只停留在应试层面&#xff0c;今天终于能详细理解一下了。参考课程为南京大学袁春风老师的计算机系统基础MOOC&#xff0c;参考书籍也是袁老师的教材&#xff0c;这是我的听课自查资料整理后的笔记&#xff0c;…

【Java笔试强训 14】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;计算日期…

web小游戏开发:华容道(一)

web小游戏开发:华容道(一) 华容道htmlcss素材原图素材验证游戏关卡华容道 老顾儿时的记忆啊,也是一个经典的益智游戏。 游戏规则就不用再介绍了吧,就是让曹操移动到曹营就算胜利。 CSDN 文盲老顾的博客,https://blog.csdn.net/superrwfei html 经过上次的扫雷,大家应…

Prometheus 监控初体验

最近由于要对Splunk 实现Prometheus 监控,下面先实践一下: 0: 先看架构图: 1: 安装: docker run -d -p 9090:9090 -v ~/docker/prometheus/:/etc/prometheus/ prom/prometheus 执行上面的 命令,发现prometheus docker 启动不起来,(原因是Mac 里的文件权限,或者是path

《嵌入式系统》知识总结4:STM32时钟源

此图说明了STM32的时钟走向&#xff0c;从图的左边开始&#xff0c;从时钟源一步步分配到外设时钟。 时钟源分类 从时钟频率来说&#xff0c;分为高速时钟和低速时钟&#xff0c;高速时钟是供给芯片主体的主时钟&#xff0c;而低速时钟只是供 给芯片中的RTC&#xff08;实时时…

Django请求生命周期

前言 django是一个web框架&#xff0c;在这之前的文章中&#xff0c;我们推导了python web框架的实现过程&#xff0c;也了解了客户端浏览器输入网址回车后发生了啥事&#xff0c;为了更加理解django的工作流程&#xff0c;本文将介绍客户端浏览器访问django后端在django框架中…

R语言多元数据统计分析在生态环境中的实践

生态环境领域研究中常常面对众多的不同类型的数据或变量&#xff0c;当要同时分析多个因变量&#xff08;y&#xff09;时需要用到多元统计分析&#xff08;multivariate statistical analysis&#xff09;。多元统计分析内容丰富&#xff0c;应用广泛&#xff0c;是非常重要和…

如何使用OpenVPN搭建局域安全网

前言: 由于在使用SpringCloud的时候把注册中心部署到内网中的一个服务器器上,由于这个服务器和我当前使用的网络的网关在同一个局域网内内,但是我电脑不在.主要现象就是我的电脑能ping通服务器,但是服务器不能ping通我的电脑 正文: 服务器端安装方式一: 去这个仓库下载一个open…

【人脸检测】——YOLO5Face: Why Reinventing a Face Detector论文浅读

人脸检测&#xff0c; yolov5 主要讨论的问题&#xff1a; 用通用的目标检测模型做人脸检测&#xff0c;而不一定需要一些专业设计的结构 摘要 最近几年在使用卷积神经网络进行人脸检测方面取得了巨大的进展。尽管许多人脸检测器使用专门用于检测人脸的设计&#xff0c;但我们…

【CTF WriteUp】2023数字中国创新大赛网络数据安全赛道决赛WP(2)

2023数字中国创新大赛网络数据安全赛道决赛WP(2) 数据分析题目 菜的要死&#xff0c;各种不会&#xff0c;答案也不全&#xff0c;凑合吧 数据分析-bankmail 流量为邮件通信流量 将其中邮件部分导出&#xff0c;保存为eml文件并打开&#xff0c;看到Alice给Bob的第一封邮件…

收藏的一些好用的网站

一、PPT模板 网址&#xff1a;https://pptmon.com/ PPTMON - Free PowerPoint Templates and Google Slides Themes 是一个提供 PowerPoint 模板和图标素材下载的网站。该网站上有大量的 PowerPoint 模板&#xff0c;可供用户根据自己的需要进行选择和下载。此外&#xff0c;该…

二叉树OJ题目合集(单值、对称、平衡、构建加遍历)

目录 前言&#xff1a; 一&#xff1a;单值二叉树 二&#xff1a;二叉树遍历 核心点 (1)前序 (2)中序 (3)后序 三&#xff1a;判断两颗树是否相同 四&#xff1a;判断二叉树是否对称 五&#xff1a;判断一颗树是否为另一颗树的子树 六&#xff1a;平衡二叉树 七&…

创建的django项目生成后,没有默认的数据库生成

目录 1、尚未执行迁移 1.1 首先&#xff0c;在setting.py文件中配置数据库链接 1.2 确保在Terminal运行已经执行了如下命令来创建数据库表格。 1.3 在数据库刷新就有了 2、已经使用了自定义的数据库 3、尚未配置默认数据库 1、尚未执行迁移 1.1 首先&#xff0c;在setting.…

介绍一款优秀的网址导航,可以部署到自己公司内部:hexo-theme-webstack

GitHub - HCLonely/hexo-theme-webstack: A hexo theme based on webstack. | 一个基于webstack的hexo主题。 中文文档 A Hexo theme based on WebStackPage. Installation hexo > 4.0 git clone https://github.com/HCLonely/hexo-theme-webstack themes/webstack hexo …

C++中的stack容器

文章目录 stack的介绍stack的使用 stack的介绍 stack是一种容器适配器&#xff0c;专门用在具有后进先出操作特性的环境中&#xff0c;只能在容器的一端进行插入删除&#xff1b;stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特性类封装作为其底层的容器&#xf…