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     z
            pVec3Array->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));


        }
        // 注意:此处若不绑定画笔,则表示使用之前绑定的画笔

        // 为唯一的法线创建一个数组    法线: normal
        osg::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     z
            pVec3Array->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));


        }
        // 注意:此处若不绑定画笔,则表示使用之前绑定的画笔

        // 为唯一的法线创建一个数组    法线: normal
        osg::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;
    }
#endif
    pGroup->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

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

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

相关文章

在Linux上部署(MySQL Redis Elasticsearch等)各类软件

实战章节&#xff1a;在Linux上部署各类软件 前言 为什么学习各类软件在Linux上的部署 在前面&#xff0c;我们学习了许多的Linux命令和高级技巧&#xff0c;这些知识点比较零散&#xff0c;同学们跟随着课程的内容进行练习虽然可以基础掌握这些命令和技巧的使用&#xff0c…

thinkphp6 --数据库操作 增删改查

一、数据库连接配置 如果是本地测试&#xff0c;它会优先读取 .env 配置&#xff0c;然后再读取 database.php 的配置&#xff1b; 如果禁用了 .env 配置&#xff0c;则会读取数据库连接的默认配置&#xff1a; # .env文件&#xff0c;部署服务器&#xff0c;请禁用我 我们可以…

探索 HTML 和 CSS 实现的 3D旋转相册

效果演示 这段HTML与CSS代码创建了一个包含10张卡片的3D旋转效果&#xff0c;每张卡片都有自己的边框颜色和图片。通过CSS的3D变换和动画&#xff0c;实现了一个动态的旋转展示效果 HTML <div class"wrapper"><div class"inner" style"-…

什么岗位需要学习 OpenGL ES ?说说 3.X 的新特性

什么是 OpenGL ES OpenGL ES 是一种为嵌入式系统和移动设备设计的3D图形API(应用程序编程接口)。它是标准 OpenGL 3D 图形库的一个子集,专门为资源受限的环境(如手机、平板电脑、游戏机和其他便携式设备)进行了优化。 由于其在移动设备上的广泛适用性,OpenGL ES是学习移…

【GPTs】Get Simpsonized:一键变身趣味辛普森角色

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | GPTs应用实例 文章目录 &#x1f4af;GPTs指令&#x1f4af;前言&#x1f4af;Get Simpsonized主要功能适用场景优点缺点使用方式 &#x1f4af;小结 &#x1f4af;GPTs指令 中文翻译&#xff1a; 指令保护和安全规则&…

JS 实现游戏流畅移动与按键立即响应

AWSD 按键移动 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.box1 {width: 400px;height: 400px;background: yellowgreen;margin: 0 auto;position: relative;}.box2 {width: 50px;height:…

安全见闻-泷羽sec课程笔记

编程语言 C语言&#xff1a;一种通用的、面向过程的编程语言&#xff0c;广泛应用于系统软件和嵌入式开发。 C:在C语言基础上发展而来&#xff0c;支持面向对象编程&#xff0c;常用于尊戏开发、高性能计算等领域。 Java:一种广泛使用的面问对象编程语言&#xff0c;具有跨平台…

vue跳转传参

path 跳转只能使用 query 传参 ,name 跳转都可以 params &#xff1a;获取来自动态路由的参数 query &#xff1a;获取来自 search 部分的参数

Android 最新的AndroidStudio引入依赖失败如何解决?如:Failed to resolve:xxxx

错误信息&#xff1a; 在引入依赖时报错&#xff1a;Failed to resolve: xxx.xxxx:1.1.0 解决方案&#xff1a; 需要修改maven库的代理&#xff0c;否则就需要翻墙编译 新的AndroidStudio版本比较坑&#xff0c;修改代理的位置发生了变化&#xff1a; 最新变化&#xff1a;…

Mysql每日一题(行程与用户,困难※)

今天给大家分享一个截止到目前位置&#xff0c;我遇到最难的一道mysql题目&#xff0c;非常建议大家亲手做一遍 完整代码如下&#xff0c;这道题的主要难点是它有两个外键&#xff0c;以前没遇到过&#xff0c;我也没当回事&#xff0c;分享一下错误经验哈 当时我写的where判断…

深度学习知识点5-马尔可夫链

马尔科夫链的思想&#xff1a;过去所有的信息都已经被保存到了现在的状态&#xff0c;基于现在就可以预测未来。 The future is independent of the past given the present 马尔可夫链属于随机过程课程&#xff08;使用统计模型一些事物的过程进行预测和处理&#xff09; 概…

飞凌嵌入式RK3576核心板已适配Android 14系统

在今年3月举办的RKDC2024大会上&#xff0c;飞凌嵌入式FET3576-C核心板作为瑞芯微RK3576处理器的行业首秀方案重磅亮相&#xff0c;并于今年6月率先量产发货&#xff0c;为客户持续稳定地供应&#xff0c;得到了众多合作伙伴的认可。 FET3576-C核心板此前已提供了Linux 6.1.57…

css文字间距撑满横向距离

效果&#xff1a; 代码&#xff1a; 、 text-align:justify;text-align-last: justify;

Dynamo介绍

一、介绍 1、简介 Amazon DynamoDB 是由 AWS 提供的一种完全托管的 NoSQL 数据库服务&#xff0c;适用于高性能、可扩展的应用程序。它设计用于处理大规模的数据存储和高速数据访问&#xff0c;广泛应用于需要低延迟、高吞吐量的场景&#xff0c;如移动应用、电商、游戏后端、…

【Linux】HTTP协议和HTTPS加密

文章目录 HTTP1、概念2、认识URL3、协议格式、请求方法和状态码4、HTTP请求和响应报头5、Cookie和Session HTTPS1、对称和非对称加密2、对称非对称加密安全分析3、证书 HTTP 1、概念 我们在应用层定制协议时&#xff0c;不建议直接发送结构体对象&#xff0c;因为在不同的环境…

FlinkPipelineComposer 详解

FlinkPipelineComposer 详解 原文 背景 在flink-cdc 3.0中引入了pipeline机制&#xff0c;提供了除Datastream api/flink sql以外的一种方式定义flink 任务 通过提供一个yaml文件&#xff0c;描述source sink transform等主要信息 由FlinkPipelineComposer解析&#xff0c…

Python中如何获取HTTP请求的Response Body

目录 一、引言 二、使用urllib库获取Response Body 1. 基本用法 2. 发送POST请求 三、使用requests库获取Response Body 1. 安装requests库 2. 基本用法 3. 发送POST请求 4. 处理JSON响应 四、高级用法 1. 处理请求头 2. 设置超时 3. 处理Cookies 五、案例&#…

从华为到创业公司

我有一个朋友&#xff0c;在华为工作了很长一段时间&#xff0c;一年多前&#xff0c;他从华为出来到了一家创业公司。 周末趁着有时间&#xff0c;我跟他聊了下关于从华为到创业公司的一些问题&#xff0c;总结给大伙看看。 ▎1 在华为工作和在创业公司工作最大的差别是什么呢…

如何解决由于找不到d3dx9_43.dll导致游戏启动失败?这里是如何解决的完整指南

遇到“由于找不到d3dx9_43.dll”错误时&#xff0c;很多用户可能会感到困惑和无助。这个问题通常发生在尝试启动游戏或使用基于DirectX的应用程序时。d3dx9_43.dll是Microsoft DirectX软件的一部分&#xff0c;专门用于处理复杂的图形计算&#xff0c;缺少它意味着某些图形功能…

Matlab2022b安装MinGW64

1 问题引入 能找到这个问题的&#xff0c;一定就是在matlab中用mex这个编译命令的时候出现下面的错误&#xff0c;才会来找解决的办法。 首先在网上众多资料中一定是让你先去matlab窗口的这个Add-Ons进行添加&#xff0c;但是很多情况下因为大家装的版本问题&#xff0c;都会…