OSG开发笔记(三十一):OSG中LOD层次细节模型介绍和使用

​若该文为原创文章,未经允许不得转载
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/143697554
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

OSG开发专栏(点击传送门)

上一篇:《OSG开发笔记(三十):OSG加载动力学仿真K模型文件以及测试Demo》
下一篇: 持续补充中…


前言

  模型较大的时候,出现卡顿,那么使用LOD(细节层次)进行层次细节调整,可以让原本卡顿的模型变得不卡顿。
  本就是LOD介绍。


Demo

  请添加图片描述


LOD

概述

  LOD也称为层次细节模型,是一种实时三维计算机图形技术,旨在通过根据物体在场景中的位置和重要性动态调整其渲染的详细程度,从而提高渲染效率和性能。
  视点离物体近时,能观察到的模型细节丰富;视点远离模型时,观察到的细节逐渐模糊。系统绘图程序根据一定的判断条件,选择相应的细节进行显示,从而避免了因绘制那些意义相对不大的细节而造成的时间浪费,同时有效地协调了画面连续性与模型分辨率的关系。

Osg::LOG节点

  在OSG中,LOD技术通过osg::LOD节点来实现。osg::LOD节点是一个特殊的场景节点,它可以包含多个子节点,每个子节点代表一个不同详细程度的模型。根据视点与物体的距离或屏幕上的像素大小,osg::LOD节点会选择相应的子节点进行渲染。

子节点的添加

  通过addChild方法,可以将不同详细程度的模型作为子节点添加到osg::LOD节点中。每个子节点都需要指定一个距离范围(或像素大小范围),在这个范围内,该子节点会被渲染。

距离和像素大小模式

  osg::LOD节点支持两种切换模式距离模式和像素大小模式。

  • 距离模式:根据视点到物体包围盒中心的距离来选择子节点;
  • 像素大小模式:根据物体在屏幕上的像素大小来选择子节点。

中心模式的设置

  对于距离模式,osg::LOD节点还支持两种中心模式:包围盒中心模式和自定义中心模式。包围盒中心模式使用物体的包围盒中心作为计算距离的点;自定义中心模式则允许用户指定一个自定义的中心点。
  LOD技术的优点和应用

  • 提高渲染效率:通过动态调整模型的详细程度,LOD技术可以显著减少需要渲染的多边形数量,从而提高渲染速度。
  • 优化内存使用:虽然OSG中的osg::LOD节点会一次性载入所有模型进入内存,但它只是有选择地进行绘制,这仍然有助于优化内存使用,因为不需要为每个模型都分配独立的内存空间。此外,OSG还提供了osg::PagedLOD节点,它支持动态分页加载,可以根据需要来加载模型文件,进一步优化内存使用。
  • 提升视觉效果:LOD技术可以在保证视觉效果的前提下,通过简化模型来减少渲染负担,从而允许开发者在场景中放置更多的物体或实现更复杂的视觉效果。
  • 广泛的应用场景:LOD技术适用于各种需要高效渲染的三维场景,如城市规划、地形渲染、游戏开发等。在这些场景中,物体的数量和详细程度往往非常高,使用LOD技术可以显著提高渲染性能和用户体验。

LOD技术的局限性

  尽管LOD技术具有诸多优点,但它也存在一些局限性。例如,在切换不同详细程度的模型时,可能会出现视觉上的跳跃现象,特别是当两个模型之间的详细程度差异较大时。此外,设计和管理不同详细程度的模型也需要一定的时间和资源投入。

其他

  OSG中的LOD技术是一种高效且灵活的三维渲染技术,它通过动态调整模型的详细程度来优化渲染性能和内存使用。在开发大规模三维场景时,LOD技术是一个不可或缺的工具。


LOD实现

  模型就不多说了,关键就是osg::Lod结点,如何添加的问题:

            // 添加模式,0~100范围内使用线模型pLod->addChild(pGeode, 0, 100);

  在这里插入图片描述

           // 添加模型,非设置的范围内的都是这个
//            pLod->addChild(pGeode); // 不能使用,预想中是没设置的都使用这个,实际上这个函数实际无用,反正都不显示pLod->addChild(pGeode, 100, 1000);

  在这里插入图片描述


Demo关键源码

绘制部分

// 绘图
{
#if 1// 第一个模型for(int partIndex = 0; partIndex < kMode.listPart.size(); partIndex++){// 创建一个用户保存几何信息的对象osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;// 创建四个顶点的数组osg::ref_ptr<osg::Vec3Array> pVec3Array = new osg::Vec3Array;// 添加四个顶点pGeometry->setVertexArray(pVec3Array.get());// 创建四种颜色的数据osg::ref_ptr<osg::Vec4Array> pVec4Array = new osg::Vec4Array;// 添加四种颜色pGeometry->setColorArray(pVec4Array.get());// 绑定颜色pGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);double r, g, b;r = 1.0f;g = 1.0f;b = 0.0f;for(int elementShellIndex = 0; elementShellIndex < kMode.listPart.at(partIndex).listElementShell.size(); elementShellIndex++){//                               x     y     zpVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).z));//                               r    g    b    a(a设置无效,估计需要其他属性配合)pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));}// 注意:此处若不绑定画笔,则表示使用之前绑定的画笔// 为唯一的法线创建一个数组    法线: normalosg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;pGeometry->setNormalArray(pVec3ArrayNormal.get());pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL);pVec3ArrayNormal->push_back(osg::Vec3(0.0, -1.0, 0.0));// 由保存的数据绘制四个顶点的多边形pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, kMode.listPart.at(partIndex).listElementShell.size() * 4));
//            pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));// 向Geode类添加几何体(Drawable)osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;pGeode->addDrawable(pGeometry.get());
#if 1// 线宽模式{osg::ref_ptr<osg::StateSet> pStateSet = pGeometry->getOrCreateStateSet();osg::ref_ptr<osg::PolygonMode> pPolygonMode = new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);pStateSet->setAttribute(pPolygonMode);}
#endif// 添加模式,0~100范围内使用线模型pLod->addChild(pGeode, 0, 100);// 只是用一个部件break;}
#endif
#if 1// 第一个模型for(int partIndex = 0; partIndex < kMode.listPart.size(); partIndex++){// 创建一个用户保存几何信息的对象osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;// 创建四个顶点的数组osg::ref_ptr<osg::Vec3Array> pVec3Array = new osg::Vec3Array;// 添加四个顶点pGeometry->setVertexArray(pVec3Array.get());// 创建四种颜色的数据osg::ref_ptr<osg::Vec4Array> pVec4Array = new osg::Vec4Array;// 添加四种颜色pGeometry->setColorArray(pVec4Array.get());// 绑定颜色pGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);double r, g, b;r = 1.0f;g = 1.0f;b = 0.0f;for(int elementShellIndex = 0; elementShellIndex < kMode.listPart.at(partIndex).listElementShell.size(); elementShellIndex++){//                               x     y     zpVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n1).z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n2).z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n3).z));pVec3Array->push_back(osg::Vec3(kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).x,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).y,kMode.hashNid2Node.value(kMode.listPart.at(partIndex).listElementShell.at(elementShellIndex).n4).z));//                               r    g    b    a(a设置无效,估计需要其他属性配合)pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));pVec4Array->push_back(osg::Vec4(r, g, b, 1.0));}// 注意:此处若不绑定画笔,则表示使用之前绑定的画笔// 为唯一的法线创建一个数组    法线: normalosg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;pGeometry->setNormalArray(pVec3ArrayNormal.get());pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL);pVec3ArrayNormal->push_back(osg::Vec3(0.0, -1.0, 0.0));// 由保存的数据绘制四个顶点的多边形pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, kMode.listPart.at(partIndex).listElementShell.size() * 4));
//            pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));// 向Geode类添加几何体(Drawable)osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;pGeode->addDrawable(pGeometry.get());// 添加模型,非设置的范围内的都是这个
//            pLod->addChild(pGeode); // 不能使用,预想中是没设置的都使用这个,实际上这个函数实际无用,反正都不显示pLod->addChild(pGeode, 100, 1000);// 只是用一个部件break;}
#endifpGroup->addChild(pLod);
}

工程模板v1.34.0

  在这里插入图片描述


入坑

入坑:复制osg::ref_ptr相关类失败

问题

  想深度复制一个模型,做lod,复制编译不过
  在这里插入图片描述

原理

  加了osg::ref_ptr,不能常规方法复制,也尝试使用get()之后在*取其类实体(非指针),也报错。
  下面是浅拷贝的示例:
  在这里插入图片描述

  无法直接深拷贝,osg::ref_ptrosg::Geometry 本身并不提供直接的深拷贝功能,因为 osg::ref_ptr 只是一个智能指针,它管理对象的生命周期,但并不关心对象的具体内容或如何复制这些内容。深拷贝通常涉及到对象的逐字段复制,这通常需要在对象类内部实现,或者通过外部函数来实现。
  在 OpenSceneGraph(OSG)中,osg::Geometry 类没有内置的深拷贝方法,因此需要自己实现深拷贝逻辑。这通常包括复制几何体的所有属性,如顶点数组、颜色数组、法线数组、纹理坐标数组、图元集等。

解决

  直接复制前面一段代码,区别得地方调整下,当作新模型加入。

入坑二:lod添加节点不设置范围的不显示

问题

  lod添加节点不设置范围的不显示

原理

  这个函数看起来就是没用,改成都设置范围

解决

  在这里插入图片描述

上一篇:《OSG开发笔记(三十):OSG加载动力学仿真K模型文件以及测试Demo》
下一篇: 持续补充中…


本文章博客地址:https://blog.csdn.net/qq21497936/article/details/143697554

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VMWare虚拟机NAT模式下与外部主机(非宿主机)通信

VMWare虚拟机NAT模式下与外部主机(非宿主机)通信 1. VMWare虚拟机网络 VMWare的三种网络工作模式&#xff1a; Bridged&#xff1a;桥接模式NAT&#xff1a;网络地址转换模式Host-Only &#xff1a;仅主机模式 VMWare 网络连接配置界面如下&#xff1a; 在本次测试环境中&a…

IDEA连接不同种类数据库

首先添加驱动 到了添加页面后&#xff0c;引入驱动jar包 添加URL样版&#xff08;我这来添加的是瀚高数据库&#xff0c;Key-Value&#xff09;也可以看上图中URL Templates Key&#xff1a;default Value&#xff1a;jdbc:highgo://{host::localhost}?[:{port::5866}][/{data…

测试实项中的偶必现难测bug--<pre>标签问题

问题描述: 用户从网上copy的简介信息可能带有<pre>标签,导致安卓上的内容只能一行滑动展示,但是ios有对这个标签做特殊处理: 分析: <pre> 标签是 HTML 中用于表示预格式化文本的标签,它的作用是保留文本中的空格、换行和缩进。它的全称是 preformatted text…

Pencils Protocol 上线新板块 Auction,生态版图进一步完善

Pencils Protocol 上线了又一新产品板块 Auction&#xff0c;预示着生态版图的进一步完善&#xff0c;该板块的推出无论是对于 Pencils Protocol 协议本身&#xff0c;还是 Scroll 生态都是极为重要的。 社区正在成为主导加密市场发展的重要力量 自 DeFi Summer 以来&#xff…

人才流失预测模型(机器学习)

1. 项目描述 ​ 企业的快速发展离不开人才的支撑&#xff0c;可是现在我国的企业的人才流失严重&#xff0c;人才流失问题现在已经成为了关系企业发展的一个重大的问题。这些企业要想在目前激烈的竞争中快速发展&#xff0c;就需要依靠自身的人力资源的来竞争。只有拥有比对方…

掌握核密度图:精准描绘不同年龄段的血糖分布

在医学研究中&#xff0c;数据的可视化是理解复杂信息和做出科学决策的关键。今天&#xff0c;我们将深入探讨一种强大的数据可视化工具——核密度图&#xff08;Kernel Density Plot&#xff0c;简称KDE&#xff09;&#xff0c;并通过Python代码实例&#xff0c;展示如何基于…

C++ 语言实现读写.csv文件.xls文件

C 语言实现读写.csv文件.xls文件 C 语言实现读.csv文件.xls文件 VNAM1_24100078.csv 文件内容&#xff1a; #include <stdio.h> #include <windows.h> #include <iostream> #include <string> #include <fstream> #include <sstream> #i…

萤石设备视频接入平台EasyCVR海康私有化视频平台监控硬盘和普通硬盘有何区别?

在现代安防监控领域&#xff0c;对于数据存储和视频处理的需求日益增长&#xff0c;特别是在需要长时间、高稳定性监控的环境中&#xff0c;选择合适的存储设备和监控系统显得尤为重要。本文将深入探讨监控硬盘与普通硬盘的区别&#xff0c;并详细介绍海康私有化视频平台EasyCV…

Ubuntu 的 ROS2 操作系统turtlebot3环境搭建

引言 本文介绍如何在 Ubuntu 系统上为 TurtleBot3 配置 ROS2 环境&#xff0c;提供详细的操作步骤以便在 PC 端控制 TurtleBot3。 本文适用于 ROS2 Humble 的安装与配置&#xff0c;涵盖必要的依赖包和 Gazebo 仿真环境的设置&#xff0c;帮助用户避免在环境搭建过程中遇到的兼…

探索 Seata 分布式事务

Seata&#xff08;Simple Extensible Autonomous Transaction Architecture&#xff09;是阿里巴巴开源的一款分布式事务解决方案&#xff0c;旨在帮助开发者解决微服务架构下的分布式事务问题。它提供了高效且易于使用的分布式事务管理能力&#xff0c;支持多种事务模式&#…

ESLint 使用教程(四):ESLint 有哪些执行时机?

前言 ESLint 作为一个静态代码分析工具&#xff0c;可以帮助我们发现和修复代码中的问题&#xff0c;保持代码风格的一致性。然而&#xff0c;ESLint的最佳实践不仅仅在于了解其功能&#xff0c;更在于掌握其执行时机。本文将详细介绍ESLint在不同开发阶段的执行时机&#xff…

关于分治法左右区间单调遍历应该如何设计

阅读以下文章&#xff0c;首先至少要求通过一道分治法的题目或听过一道该类型的讲解。 对于分治的题目&#xff0c;想必你应该知道&#xff0c;通常我们是对于一个区间拆分两个部分&#xff0c;而最小子问题通常是只包含一个元素的区间数组。为了后续方便处理更大范围的区间&am…

【网络协议栈】网络层(上)网络层的基本理解、IP协议格式、网络层分组(内附手画分析图 简单易懂)

绪论​ “It does not matter how slowly you go as long as you do not stop.”。本章是自上而下的进入网络协议栈的第三个篇幅–网络层–&#xff0c;本章我将带你了解网络层&#xff0c;以及网络层中非常重要的IP协议格式和网络层的分片组装问题&#xff0c;后面将持续更新网…

利用AI制作《职业生涯规划PPT》,10分钟完成

职业生涯规划是大学生活中非常重要的一环。通过制定职业规划&#xff0c;你能够明确未来的职业目标、认清自身的优劣势&#xff0c;进而制定切实可行的计划&#xff0c;以便顺利踏上职业发展的道路。而制作一份精美的职业生涯规划PPT&#xff0c;能有效帮助你在面试、职业规划报…

FPGA高速设计之Aurora64B/66B的应用与不足的修正

FPGA高速设计之Aurora64B/66B的应用与不足的修正 Aurora IP协议的特点 首先基于网上找到的一些资料&#xff0c;来讲述下Aurora高速协议的特点与相关的应用。Aurora 协议在 2002 年由 Xilinx 公司首次提出&#xff0c;是由Xilinx提供的一个开源、免费的链路层串行传输通信协议…

vue2项目启用tailwindcss - 开启class=“w-[190px] mr-[20px]“ - 修复tailwindcss无效的问题

效果图 步骤 停止编译"npm run dev"安装依赖 npm install -D tailwindcssnpm:tailwindcss/postcss7-compat postcss^7 autoprefixer^9 创建文件/src/assets/tailwindcss.css&#xff0c;写入内容&#xff1a; tailwind base; tailwind components; tailwind utiliti…

Docker部署Nginx

1. 拉取Nginx镜像 1.1 选择指定版本或latest 在部署Nginx时&#xff0c;选择合适的镜像版本是至关重要的。Docker Hub上提供了Nginx的官方镜像&#xff0c;用户可以根据自己的需求选择使用特定版本的Nginx或者始终使用最新的latest标签。 版本选择的重要性&#xff1a;选择一…

WPF+MVVM案例实战与特效(二十八)- 自定义WPF ComboBox样式:打造个性化下拉菜单

文章目录 1. 引言案例效果3. ComboBox 基础4. 自定义 ComboBox 样式4.1 定义 ComboBox 样式4.2 定义 ComboBoxItem 样式4.3 定义 ToggleButton 样式4.4 定义 Popup 样式5. 示例代码6. 结论1. 引言 在WPF应用程序中,ComboBox控件是一个常用的输入控件,用于从多个选项中选择一…

ctfshow-web入门-反序列化(web271-web278)

目录 1、web271 2、web272 3、web273 4、web274 5、web275 6、web276 7、web277 8、web278 laravel 反序列化漏洞 1、web271 laravel 5.7&#xff08;CVE-2019-9081&#xff09; poc <?php namespace Illuminate\Foundation\Testing{use Illuminate\Auth\Generic…

hive数据查询语法

思维导图 基本查询 基本语法 SELECT [ALL | DISTINCT] 字段名, 字段名, ... FROM 表名 [inner | left outer | right outer | full outer | left semi JOIN 表名 ON 关联条件 ] [WHERE 非聚合条件] [GROUP BY 分组字段名] [HAVING 聚合条件] [ORDER BY 排序字段名 asc | desc…