osgGA::CameraManipulator类computeHomePosition函数分析

这篇具有很好参考价值的文章主要介绍了osgGA::CameraManipulator类computeHomePosition函数分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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中提到的经典的平头截体:

osgGA::CameraManipulator类computeHomePosition函数分析 图1 平头截体

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

 图 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.);

不懂atan2的童鞋可以参考C++中反正切atan2(y,x)与atan(x)的区别 博文。

同样地:

   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.;

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

osgGA::CameraManipulator类computeHomePosition函数分析

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

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

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

参考链接:

【1】:osg中漫游器的原理——osgGA::CameraManipulator(二)。文章来源地址https://www.toymoban.com/news/detail-430470.html

到了这里,关于osgGA::CameraManipulator类computeHomePosition函数分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Fourier分析入门——第3章——离散函数的Fourier分析

    目录 第 3 章  离散函数的Fourier分析 3.1 引言 3.2 在1点采样的函数 3.3 在2点采样的函数 3.4 Fourier分析是一种线性变换 3.5 Fourier分析是一种基向量的变更 3.6 在3点采样的函数 3.7 在D点采样的函数 3.8 整理(tidying up) 3.9 Parseval[pá:zeifa:l]定理 3.10 关联统计 3.11  图像对比和复合光栅(I

    2024年02月05日
    浏览(35)
  • ARM64函数调用流程分析

    ARM64 程序调用标准 下图是介绍一个简单函数调用的示例,在该示例中简单介绍了栈的使用。 2.1.1 main的C代码实现 2.1.2 main函数对应汇编及其分析 0000000000000114 main: main函数的入口 114: a9be7bfd stp x29, x30, [sp, #-32]! 将sp = sp - 32,为main函数开一个32Byte的栈空间,然后将x29(FP),X30(LR)寄

    2024年02月11日
    浏览(42)
  • BLHeli_S 代码分析---BLHeli.asm入口函数位置分析

    查询网络资料 汇编 代码入口位置就是 Flash 的开始位置也就是0x0000位置。 在 BLHeli.asm 文件中并未找到 0x00的位置运行相应函数,找任意一个种类电调头文件查看,此处我们查看 AIKON_Boltlite_30A.inc 文件,在该文件中找到对应0x00位置。 对应代码如下所示 由代码可知,从0x00位置开

    2024年01月19日
    浏览(45)
  • hive窗口分析函数使用详解系列二之分组排序窗口函数

    我们讨论面试中各大厂的SQL算法面试题,往往核心考点就在于窗口函数,所以掌握好了窗口函数,面对SQL算法面试往往事半功倍。 已更新第一类聚合函数类,点击这里阅读 hive窗口函数聚合函数类 本节介绍Hive聚合函数中的第二类聚合函数:分组排序窗口函数。 这些函数的用

    2024年04月13日
    浏览(36)
  • 【Python】9.函数用法和底层分析

    函数是可重用的程序代码块。函数的作用,不仅可以实现代码的复用,更能实现代码的一致性。一致性指的是,只要修改函数的代码,则所有调用该函数的地方都能得到体现。 在编写函数时,函数体中的代码写法和我们前面讲述的基本一致,只是对代码实现了封装,并增加了

    2024年02月06日
    浏览(47)
  • 1 EXCEL数据分析常用函数

    语法是 SUM(number1,[number2],…) sumif函数语法是:=SUMIF(range,criteria,sum_range) sumif函数的参数如下: 第一个参数:Range为条件区域,用于条件判断的单元格区域。 第二个参数:Criteria是求和条件,由数字、逻辑表达式等组成的判定条件。 第三个参数:Sum_range 为实际求和区域,需

    2024年02月09日
    浏览(39)
  • Scapy:sniff函数剖析(参数分析)

    sniff函数是Scapy中的探嗅函数,定义在sendrecv模块中。下面将给出sniff函数的具体剖析。 官方没有给出sniff文档,下面给出源码: 看来重点应该放在AsyncSniffer上。 源码太长,就节选调用的_run方法的函数头(_run方法本身也有207行) 参数解析: count:         类型为int,默认值

    2023年04月16日
    浏览(64)
  • 【postgresql 基础入门】聚合函数,通用型,统计分析型,多种多样的聚合函数满足数据的大数据的统计分析

    ​ 专栏内容 : postgresql内核源码分析 手写数据库toadb 并发编程 个人主页 :我的主页 管理社区 :开源数据库 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 在数据库管理系统中,SQL(结构化查询语言)的聚集函数扮演着至关重要的角色。它们能够对一组值执

    2024年04月10日
    浏览(65)
  • OpenCV每日函数 结构分析和形状描述符(9) ApproxPolyDP函数 拟合曲线

            也称为 Ramer-Douglas-Peucker 算法 或 迭代端点拟合算法, 是一种通过减少点数来平滑折线(由线性线段组成的线)的算法。简化曲线应保留原始曲线的粗略形状,但仅包含定义原始曲线的点的子集。         粗化程度由单个参数 ε 控制,该参数定义原始点和简化

    2024年02月20日
    浏览(53)
  • 【Kotlin】DSL 领域特定语言 ( apply 标准库函数分析 | 普通匿名函数 | 扩展匿名函数 | 泛型扩展匿名函数 )

    本章总结 : 读懂 apply 标准库函数 核心是其 block: T.() - Unit 参数 , 这是 泛型扩展匿名函数 ; 泛型扩展匿名函数 T.() - Unit 演变路径 : 普通匿名函数 : () - Unit , 这个函数 参数 和 返回值 都为空 ; 扩展匿名函数 : String.() - Unit , 这个函数 是 为 具体的 String 类型定义的扩展函数 ; 泛型

    2023年04月09日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包