场景图形管理 - (1)

本章主要介绍在场景图形中如何管理场景数据及交互过程,这在实际开发中非常重要。

    1. 视图与相机

        什么是视图?在《OpenGL编程指南》中有下面的比喻,从笔者开始学习图形学就影响深刻,相信对读者学习场景管理也会非常有帮助。

        产生目标场景视图的变换过程类似于用相机进行拍照,主要有如下的步骤:

  1. 把相机在脚架上,让对对准场景(视图变换)。
  2. 对场景进行安排,使照片中各物体位于读者所希望的位置(模型变换)
  3. 选择照相机镜头,并调整放大倍数《投影变换)
  4. 确定最终照片的大小,如放大(视口变换)。

当完成这些步骤以后,它就可以绘制场景了。视图可以简单理解为一个场景拍照。通过上面一个非常形象而生动的比喻,读者应该了解了三维图像的显示流程,如图 8-1 所示

图8-1 三维图像的显示流程

        将世界坐标系中的三维物体经过一系列几何变化(包括平移、旋转和伸缩等),为了使显示的物体能以合适的位置、大小和方向显示出来,必须要通过投影,然后定义一个三维视景体,对物体进行裁剪,只使投影在视景体内的部分显示出来,然后在屏幕窗口内定义一个矩形,称为视口(Viewport),视景体投影后的图形就在视口内显示,最后作一些适当变换,使图形在屏幕坐标系下显示。

     在OSG中,包含 SimpleViewerViewerCompositeViewer3大视口类。设计SimpleViewer 的目的很简单,主要是为了满足用户的需求,使一个已有的程序移植到OSG中,实现与现有框架匹配的简单视口类。对于Viewer和 CompositeViewer类,后面几节中将有专门的讲解。

      1. osg::Camera类

        osg::Camera类继承自 osg::Transformosg:CullSettings 类,用来管理OSG中的模型-视图矩阵,其继承关系图如图8-2所示。

        相机的管理主要是通过各种变换来实现的,在 OpenGL 中如此,在OSG中同样也是如此。在前面已经说到OSG中的图形的显示流程,下面详细说明各种变换。

  1. 视点变换

视点变换就是设置视点的方向和位置。默认情况下,视点定位为坐标原点,指向Y正方向。在Camera中的视点变换函数如下:

void setViewMatrixAsLookAt(const osg:Vec3d &eye, const osg::Vec3d &center, const osg::Vec3d &up)

void getViewMatrixAsLookAt(osg.:Vec3d &eye, osg::Vec3d &center, osg::Vec3d &up, double lookDistance=1.0)

void getViewMatrixAsLookAt(osg.:Vec3f &eye, osg::Vec3f &center, osg::Vec3f &up, float lookDistance=1.0)

第一个参数是视点的位置,第二个参数是参考点的位置,该点通常为场景中的中心轴上的点,第三个参数是视点向上的方向向量的方向

图8-2 osg::Camcra 的继承关系图

  1. 模型变换

模型变换就是对模型的位置、大小及角度的变换。在前面已经讲到了通过两个基本的节点-位置变换节点(osg::PositionAttitudeTransform)和矩阵变换节点(osg:MatrixTransfom)来实现模型变换这里不再重述。

  1. 投影变换

投影变换在显示流程中是一个非常重要的环节。经过模型视景的转换后,场景中的物体放在了所希望的位置上,但由于显示器只能用二维图像显示三维物体,因此就要靠投影来降低维数。

事实上,投影变换的目的就是定义一个视景体,使视景体外多余的部分被裁剪掉,最终进入图像的只是视景体内的有关部分。投影包括透视投影(Perspective Projection)正视投影(OrthographicProjection)两种

透视投影比较好理解,符合正常的视觉现象。离视点越近,物体越大;离视点越远,物体越小当远到极点时,物体消失,变成灭点。

在OSG中,有两种透视投影,即透视视景体和对称透视视景体。

  • 透视视景体的函数如下:

void setProjectionMatrixAsFrustum(double left, double right,double bottom,double top,double zNear,double zFar);

bool getProjectionMatrixAsFrustum(double &left,double &right,double &bottom,double &top,double &zNear,double &zFar);

*创建或者得到一个透视视图平截体的矩阵,并把它与当前矩阵相乘。第1-4 个参数分别是近裁剪面的参数信息,第五个参数表示从视点到近裁面的距离:第六个参数表示从视点到远裁剪面的距离,注意,zNear和zFar 必须指定为正数,如图8-3所示*/

图8-3透视投影

  • 对称透视视景体的函数如下:

void setProjectionMatrixAsPerspective(double fovy, double aspectRatio, double zNear, double zFar);

bool getProjectionMatrixAsPerspective(double &fovy, double &aspectRatio, double &zNcar, double &zFar);

/*创建或者得到一个对称透视视图的平截头体的矩阵,并与当前矩阵相乘。第一个参数表示z平面视野角度,第二个参数表示平截头的纵横比:第三个参数表示视点与近裁面的距离,第四个参数表示视点与远裁剪面的矩阵,注意,必须为正数,如图8-4所示*/

图8-4 对称透视投影

使用对称透视视景体时需要注意视野角度,如果调整不好,会导致图形的变形,就是后面会讲到的宽屏变形问题,后面会提出一种解决方案,就是通过设置对称透视视景体实现的。

正射投影也包括两种,即正射投影

  • 正射投影函数如下

void setProjcctionMatrixAsOrtho(double left, double right, double bottom, double top, double zNear, double zFar);

 bool getProjectionMatrixAsOrtho(double &lef, double &right, double &bottom, double &top, double &zNear, double&zFar);

/*创建或者得到一个平行正射投影矩阵,并与当前矩阵相乘。第1~4个参数分别是近裁剪平面的参数信息,第二个参数表示视点距近裁剪面的距离:第三个参数表示视点距远裁剪面的距离,注意,必须为正数且为不同的值,如图 8-5所示/

  • 特殊正射投影函数如下

void setProjectionMatrixAsOrtho2D(double left double right double bottom, double top)

/*创建一个表示把二维投影坐标投影到屏幕上的矩阵,并与当前矩阵相乘,第1-4个参数表示矩阵的信息*/

使用正射投影矩阵把二维图像投影到二维屏幕时,需要注意的是,要指定Near和Far分别为-1.0和 1.0当然,此时采用特殊的正射投影矩阵也可以完成这种渲染效果。

  1. 视口变换

视口变换就是将视景体内投影的物体显示在二维的视口平面上。在计算机图形学中,它的定义是将经过几何变换投影变换裁剪变换后的物体显示于屏幕窗口内指定的区域内,这个区域通常为矩形,称为视口。

视口变换函数如下:

void setViewport(osg::Viewport  viewport);

void setViewport(int x, int y,int width, int height);

const Viewport *getViewport() const;

Vicwport *getViewport();

/*创建或者得到一个视口。

第1-2个参数表示屏幕左下角的坐标:第三个参数表示屏幕宽度,第四个参数表示屏幕高度,默认情况下,表示整个屏幕大小*/

  1. 裁剪变换

在OSG中,默认了6个裁剪平面以去除没有必要显示的物体。读者还可以定义其他的裁剪平面来确定裁剪。定义裁剪平面的方法有很多,如osg::Scissorosg::ClipPlane等。

osg::ClipPlane类继承自osg::StateAttribute类,封装了OpenGL中的glClipPlane()函数,继承关系图如图8-6所示。

图8-6 osg::ClipPlane 的继承关系图

在类的成员函数中,设置裁剪平面的有下面几个函数:

void setClipPlane(const Plane &plane);

void setClipPlane(double a, double b, double c, double d);

void setClipPlane(const Vec4d &plane);

/*参数都指向一个裁剪平面,裁平面可以用 Ax+By+Cz+D-0方程表示。因此,A,B,C,D,4个数依次表示裁剪平面方程的4个参数*/

上面的方法只是设置一个裁剪平面的参数,如果想要调用该裁剪平面,还需要在属性中开启该裁剪平面,如下面的代码:

root->getOrCreateStateSet()->setAttributeAndModes(cc, osg::StateAttribute ::ON )

如果在应用程序中要指定多个裁剪平面,此时需要注意指定平面的索引,否则前面先指定的裁剪平面会被覆盖。可以使用下面的函数:

void setClipPlaneNum(unsigned int num);

unsigned int getClipPlaneNum() const;

/* 得到一个裁剪平面的索引或者指定一个平面的索引 */

osg::Scissor 类继承自 osg:StateAttribute 类装了 OpenGL 中 glScissor()函数,继承关系图如图8-7所示。

该类主要用于设置一个视口裁剪平面矩形。设置裁剪平面矩形的函数如下:

void setScissor(int x, int y, int width, int height);// 参数表示一个平面矩形的信息(左下角坐标、宽度和高度)。

上面讲了几种变换,理解这几种变换对学习后面的内容是非常有帮助的。在osgCamera类中除了定义一些基本变换以外,还添加了其他的操作,如清除背景色和清除各种缓存信息等。

清除背景色可以用下面的函数:

void setClearColor(const osg::Vec4 &color)

const osg::Vec4 & getClearColor()const

清除各种缓存信息可以用下面的函数:

void setColorMask(osg::ColorMask *colorMask):

void setColorMask(bool red, bool green, bool blue, bool alpha);

const ColorMask * getColorMask()const;

ColorMask *getColorMask0;

例如,“viewer->getCamera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);”向函数中传入OpenGL缓存标示,表示清除颜色深度和模板缓存。

      1. 裁平面示例(一)

裁剪平面(osg::ClipPlane)示例(一)的代码如程序清单8-1所示

void clipPlane_8_1(const string strDataFolder)

{

    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;

    traits->x = 40;

    traits->y = 40;

    traits->width = 600;

    traits->height = 480;

    traits->windowDecoration = true;

    traits->doubleBuffer = true;

    traits->sharedContext = 0;

    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());

    osg::ref_ptr<osg::Camera> camera = new osg::Camera;

    camera->setGraphicsContext(gc.get());

    camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));

    GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;

    camera->setDrawBuffer(buffer);

    camera->setReadBuffer(buffer);

    viewer->addSlave(camera.get());

    // 创建一个裁剪平面;

    osg::ref_ptr<osg::ClipPlane> cp1 = new osg::ClipPlane();

    // 设置裁剪平面

    cp1->setClipPlane(0, 1, 1, 1);

    // 指定平面索引

    cp1->setClipPlaneNum(0);

    // 创建一个裁剪平面

    osg::ref_ptr<osg::ClipPlane> cp2 = new osg::ClipPlane();

    // 设置裁剪平面

    cp2->setClipPlane(1, 0, 0, 1);

    // 指定平面索引

    cp2->setClipPlaneNum(1);

    osg::ref_ptr<osg::Group> root = new osg::Group();

    // 读取模型

    string strDataPath = strDataFolder + "cow.osg";

    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strDataPath);

    root->addChild(node.get());

    // 启用裁剪平面

    root->getOrCreateStateSet()->setAttributeAndModes(cp1.get(), osg::StateAttribute::ON);

    root->getOrCreateStateSet()->setAttributeAndModes(cp2.get(), osg::StateAttribute::ON);

    // 优化场景数据

    osgUtil::Optimizer optimizer;

    optimizer.optimize(root.get());

    viewer->setSceneData(root.get());

    viewer->realize();

    viewer->run();

}

运行程序,截图如图8-8所示

图8-8裁平面示例(一)截图

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JUC】七、读写锁

文章目录 1、读写锁2、读写锁的体验3、读写锁的特点4、锁的演变5、读写锁的降级6、复习&#xff1a;悲观锁和乐观锁 1、读写锁 JUC下的锁包的ReadWriteLock接口&#xff0c;以及其实现类ReentrantReadWriteLock ReadWriteLock 维护了一对相关的锁&#xff0c;即读锁和写锁&…

TikTok对文化艺术的影响:传统与现代的碰撞

在这个数字时代&#xff0c;社交媒体平台不仅改变了我们的社交方式&#xff0c;也对文化和艺术产生了深远的影响。其中&#xff0c;TikTok是一个备受欢迎的应用&#xff0c;已成为传统与现代文化艺术交汇的独特平台。本文将深入探讨TikTok对文化艺术的影响&#xff0c;以及传统…

Freeswitch中CHANNEL_HOLD保持事件

1.CHANNEL_HOLD保持事件 2023-11-15T09:18:42.6920800 INFO c.e.c.v.s.c.i.FsServerEventHandler - eventReceived:CHANNEL_HOLD 2023-11-15T09:18:42.6920800 INFO c.e.c.v.s.c.i.FsServerEventHandler - EventBody********:{variable_effective_caller_id_number1000, , va…

OpenCV必知必会基础3(包括色彩空间的变换、ROI、OpenCV中最重要的结构体Mat以及获取图像的属性)

文章目录 OpenCV的色彩空间——RGB与BGROpenCV的色彩空间——HSV与HSLHSV主要用于OpenCV中HSL OpenCV色彩空间转换YUV主要用于视频中题目 图像操作的基石Numpy【基础操作】np.arraynp.zerosnp.onesnp.fullnp.identitynp.eye Numpy基本操作之矩阵的检索与赋值Numpy基本操作三——…

Kylin-Server-V10-SP3+Gbase+宝兰德信创环境搭建

目录 一、Kylin-Server-V10-SP3 安装1.官网下载安装包2.创建 VMware ESXi 虚拟机3.加载镜像&#xff0c;安装系统 二、Gbase 安装1.下载 Gbase 安装包2.创建组和用户、设置密码3.创建目录4.解压包5.安装6.创建实例7.登录8.常见问题 三、宝兰德安装1.获取安装包2.解压安装3.启动…

黑马程序员微服务 分布式搜索引擎3

分布式搜索引擎03 0.学习目标 1.数据聚合 **聚合&#xff08;aggregations&#xff09;**可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 什么品牌的手机最受欢迎&#xff1f;这些手机的平均价格、最高价格、最低价格&#xff1f;这些手机每月的销售…

【JavaEE初阶】 HTML基础详解

文章目录 &#x1f38b;什么是HTML&#xff1f;&#x1f340;HTML 结构&#x1f6a9;认识标签&#x1f6a9;HTML 文件基本结构&#x1f6a9;快速生成代码框架 &#x1f384;HTML 常见标签&#x1f6a9;注释标签&#x1f6a9;标题标签: h1-h6&#x1f6a9;段落标签: p&#x1f6…

【差旅游记】启程-新疆哈密(2)

哈喽&#xff0c;大家好&#xff0c;我是雷工。 最近需要出差&#xff0c;11月02号第一次去新疆特意记录下去新疆的过程。 01 又过北京西站 本来订的是途径成都中转的路线&#xff0c;结果飞机改点&#xff0c;中转时间太短导致赶不上下班飞机&#xff0c;只好改道北京。 又到…

c# - - - Application.StartupPath(程序安装目录)和Environment.CurrentDirectory(程序工作目录)

Application.StartupPath 应用程序的安装目录&#xff0c;不会改变。 在C:\Users\Administrator\source\repos\ConsoleApp6\bin\Debug目录中&#xff0c;运行ConsoleApp6.exe。 安装目录为&#xff1a;C:\Users\Administrator\source\repos\ConsoleApp6\bin\Debug 在C:\Users…

【文件读取/包含】任意文件读取漏洞 afr_1

1.1漏洞描述 漏洞名称任意文件读取漏洞 afr_1漏洞类型文件读取漏洞等级⭐漏洞环境docker攻击方式 1.2漏洞等级 高危 1.3影响版本 暂无 1.4漏洞复现 1.4.1.基础环境 靶场docker工具BurpSuite 1.4.2.靶场搭建 1.创建docker-compose.yml文件 version: 3.2 services: web: …

EMNLP 2023 | 用于开放域多跳推理的大语言模型的自我提示思想链

©PaperWeekly 原创 作者 | 王金元 单位 | 上海交通大学 研究方向 | 大模型微调及应用 论文标题&#xff1a; Self-prompted Chain-of-Thought on Large Language Models for Open-domain Multi-hop Reasoning 模型&代码地址&#xff1a; https://github.com/noewangj…

idea中git 移除对某个文件的跟踪

应用场景如下 某个log 文件&#xff0c;被同事用git 提交到了服务器&#xff0c;本地拉去之后我们的跟踪也会受影响 取消跟踪的方法如下&#xff1a; 删除本地缓存 git rm --cached "logs/test.log" 提交无效的log git commit -m "ignore log" 再将lo…

三子棋——C语言初阶

一.游戏思路&#xff1a; 设计菜单&#xff0c;选择开始游戏(1)还是退出游戏(0)&#xff08;若是输入数字不再输入范围内&#xff0c;则“选择错误”&#xff09;初始化棋盘打印棋盘&#xff08;步骤二和三不可调换位置&#xff09;玩家下棋&#xff08;坐标落子&#xff09;—…

Java排序算法之堆排序

图解 堆排序是一种常见的排序算法&#xff0c;它借助了堆这种数据结构。堆是一种完全二叉树&#xff0c;它可以分为两种类型&#xff1a;最大堆和最小堆。在最大堆中&#xff0c;每个结点的值都大于等于它的子结点的值&#xff0c;而在最小堆中&#xff0c;每个结点的值都小于等…

力扣第84 题柱状图中最大的矩形 C++ 单调栈 Java

题目 84. 柱状图中最大的矩形 困难 相关标签 栈 数组 单调栈 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heigh…

MySQL(18):MySQL8.0的其它新特性

MySQL从5.7版本直接跳跃发布了8.0版本。 MySQL8.0 新增特征 1.更简便的NoSQL支持。 NoSQL泛指非关系型数据库和数据存储。随着互联网平台的规模飞速发展&#xff0c;传统的关系型数据库已经越来越不能满足需求。从5.6版本开始&#xff0c;MySQL就开始支持简单的NoSQL存储功能…

给女朋友开发个小程序低价点外卖吃还能赚钱

前言 今天又是无聊的一天,逛了下GitHub,发现一个库里面介绍美团饿了吗外卖红包外卖优惠券,先领红包再下单。外卖红包优惠券,cps分成,别人领红包下单,你拿佣金。哇靠,那我岂不是可以省钱还可以赚钱,yyds。。。。想想都美好哈哈哈!!! 回到正题,这个是美团饿了么分销…

基于51单片机电子钟温度计数码显示设计( proteus仿真+程序+设计报告+讲解视频)

这里写目录标题 ✅1.主要功能&#xff1a;✅讲解视频&#xff1a;✅2.仿真设计✅3. 程序代码✅4. 设计报告✅5. 设计资料内容清单&&下载链接✅[资料下载链接&#xff1a;](https://docs.qq.com/doc/DS0Nja3BaQmVtWUpZ) 基于51单片机电子钟温度检测数码显示设计( proteu…

【文件读取/包含】任意文件读取漏洞 afr_3

1.1漏洞描述 漏洞名称任意文件读取漏洞 afr_3漏洞类型文件读取/包含漏洞等级⭐⭐⭐⭐⭐漏洞环境docker攻击方式 1.2漏洞等级 高危 1.3影响版本 暂无 1.4漏洞复现 1.4.1.基础环境 靶场docker工具BurpSuite 1.4.2.环境搭建 1.创建docker-compose.yml文件 version: 3.2 servi…

VSCode配置ESP-IDF

参考其他 文章即可 如果编译时遇到问题&#xff0c;就去找环境变量&#xff0c;多半是环境变量没有配置好。根据自己安装的idf的目录重新配置 环境变量. 如果电脑上有python环境&#xff0c;但是编译时出现找不到python解释器&#xff0c;需要执行下面命令&#xff0c;另外重…