osg利用setNodeMask和Switch隐藏节点用法说明

news2024/11/16 21:31:08

目录

1. 用法及差异点说明

2.利用NodeMask隐藏节点

2. Switch节点

3. NodeMask和Switch混用


1. 用法及差异点说明

     在osg中使Node隐藏方式有两种,一种是设置NodeMask,另外一种是使用osg的Switch类来控制。两者的区别:前者只是看不到,数据还在场景中,隐藏节点并不能影响渲染性能,不会降低内存消耗;后者是从内存中暂时移除节点,可以降低内存消耗,会提高渲染性能,需要显示时再加载进场景。对于大型复杂且暂时不需要显示的节点,采用osg::Switch将节点移出不显示该节点,可以大大提供渲染性能,降低系统内存消耗。

2.利用NodeMask隐藏节点

如下代码:

// showOrHideNode.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<osgViewer/Viewer>
#include<osg/ArgumentParser>
#include<osgDB/readFile>
#include<osg/Group>
#include<osg/Switch>
#include<osg/PositionAttitudeTransform>
using namespace osg;
int main()
{
	auto spCowNode = osgDB::readRefNodeFile("cow.osg");
	if (nullptr == spCowNode)
	{
		osg::notify(osg::FATAL) << "cow node is null\r\n";
		return 1;
	}

	auto pGroup = new osg::Group();
	pGroup->addChild(spCowNode);

	osgViewer::Viewer viewer;
	auto pCamera = viewer.getCamera();
	auto defaultCullMask = pCamera->getCullMask();      // 相机默认的裁剪掩码
	auto defaultCowNodeMask = spCowNode->getNodeMask(); // 奶牛节点默认的掩码
	std::cout.setf(std::cout.hex, std::cout.basefield); // 以16进制输出掩码值
	std::cout.setf(std::cout.showbase);                 // 显示16进制前面的ox
	std::cout << "default Cull Mask of camera is : " << defaultCullMask << std::endl;
	std::cout << "default  Mask of cow node is : " << defaultCowNodeMask << std::endl;
	// pCamera->setCullMask(0x0); // 这里将相机裁剪掩码设置为0,即所有节点都被裁剪,不被渲染,此时视景器中的场景是空的,任何场景都不会绘制
	spCowNode->setNodeMask(0x0); // 更改奶牛的节点掩码值为0,则奶牛不会被渲染即不会在视景器中绘制
	
	viewer.setSceneData(pGroup);
	return viewer.run();

}
 

控制台输出如下:

视景器中没有任何场景节点,即是空的,因为是空的,就不贴图了。 

说明:

  • 如果取消上面代码第32行注释,即将相机裁剪掩码设置为0,则场景中所有节点都被裁剪掉,不会被渲染,此时视景器中的场景是空的,任何节点都不会绘制。
  • 因为第33行设置奶牛的节点掩码为0,则奶牛不会被渲染,此时视景器中的场景是空的。
  • 默认情况下,节点掩码和相机裁剪掩码都为 0xffffffff,即int类型的最大值。

osg幕后实现的原理:

       节点掩码是一系列的位集合,默认值是0xffffffff,即所有的位都被设置。节点掩码最常用的作用是用在遍历场景树中。例如:当利用osg::NodeVisitor遍历场景树时,将遍历掩码(TraversalMask)和节点掩码(NodeMask)进行位与(&)操作,从而决定该节点是否被处理或遍历。例如:一个节点通过如下代码设置其掩码为0x02:

spNode->setNodeMask(0x02); 

而通过如下代码:

osgViewer::Viewer viewer;
auto pCamera = viewer.getCamera();
pCamera->setCullMask(0x04); 

将相机的裁剪掩码设置为0x04。当利用osg::NodeVisitor遍历场景树时,会将相机的裁剪掩码即这里的0x04作为遍历掩码(TraversalMask)然后再&上节点掩码(NodeMask)0x02,如下:

TraversalMask & NodeMask = 0x04 & 0x02 = 0100 & 0010 = 0000

结果为0,则该节点及其下面的子节点被相机忽略即被裁剪掉,因此不会被渲染绘制。相反地,将相机的裁剪掩码设置为0x03,则:

TraversalMask & NodeMask = 0x03 & 0x02 = 0011 & 0010 = 0010

结果为二进制10即十进制2,不为0,则该节点及其下面的子节点不会被相机裁剪,因此会被渲染绘制。

总结:

      节点是否会被渲染或裁剪,取决于相机裁剪掩码和节点掩码&之后的值,该值如果为1,则该节点会被渲染;为0,则会被相机裁剪,不会被渲染。

2. Switch节点

如下代码:

// showOrHideNode.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<osgViewer/Viewer>
#include<osg/ArgumentParser>
#include<osgDB/readFile>
#include<osg/Group>
#include<osg/Switch>
#include<osg/PositionAttitudeTransform>
using namespace osg;
int main()
{
	auto spCowNode = osgDB::readRefNodeFile("cow.osg");
	if (nullptr == spCowNode)
	{
		osg::notify(osg::FATAL) << "cow node is null\r\n";
		return 1;
	}

	auto pGroup = new osg::Group();
		
	ref_ptr<osg::Switch> spSwitchNode = new osg::Switch();
	spSwitchNode->addChild(spCowNode);
	spSwitchNode->setValue(0, false); // 第1个参数表示孩子节点在osg::Switch节点中的索引,因为只有一个奶牛节点,所以索引为0
	pGroup->addChild(spSwitchNode);

	osgViewer::Viewer viewer;
	viewer.setSceneData(pGroup);
	return viewer.run();

}
 

说明:

  • osg::Switch中的setValue函数的第1个参数表示孩子节点在osg::Switch节点中的索引,因为只有一个奶牛节点,所以索引为0。
  • osg::Switch中的setValue函数的第2个参数表示是隐藏还是显示该孩子节点,true为显示;false表示隐藏。

3. NodeMask和Switch混用

如下代码:

// showOrHideNode.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<osgViewer/Viewer>
#include<osg/ArgumentParser>
#include<osgDB/readFile>
#include<osg/Group>
#include<osg/Switch>
#include<osg/PositionAttitudeTransform>
using namespace osg;
int main()
{
	auto spCowNode = osgDB::readRefNodeFile("cow.osg");
	if (nullptr == spCowNode)
	{
		osg::notify(osg::FATAL) << "cow node is null\r\n";
		return 1;
	}

	auto pGroup = new osg::Group();
	pGroup->addChild(spCowNode);

	osgViewer::Viewer viewer;
	auto pCamera = viewer.getCamera();
	auto defaultCullMask = pCamera->getCullMask();      // 相机默认的裁剪掩码
	auto defaultCowNodeMask = spCowNode->getNodeMask(); // 奶牛节点默认的掩码
	std::cout.setf(std::cout.hex, std::cout.basefield); // 以16进制输出掩码值
	std::cout.setf(std::cout.showbase);                 // 显示16进制前面的ox
	std::cout << "default Cull Mask of camera is : " << defaultCullMask << std::endl;
	std::cout << "default  Mask of cow node is : " << defaultCowNodeMask << std::endl;
	spCowNode->setNodeMask(0x0); // 隐藏奶牛节点

	ref_ptr<osg::PositionAttitudeTransform> spPosNode = new osg::PositionAttitudeTransform;
	spPosNode->addChild(spCowNode);
	spPosNode->setPosition(osg::Vec3d(10.0, 0.0, 0.0));

	ref_ptr<osg::Switch> spSwitchNode = new osg::Switch();
	spSwitchNode->addChild(spPosNode);
	spSwitchNode->setValue(0, true); // 显示奶牛节点
	pGroup->addChild(spSwitchNode);

	viewer.setSceneData(pGroup);
	return viewer.run();

}

说明:

  • 上述代码NodeMask和Switch节点都将同一个奶牛节点作为其孩子节点,并进行隐藏与显示。如果NodeMask和Switch节点同时对同一节点进行显示隐藏控制,则最终显示隐藏的结果以NodeMask为主,即NodeMask比Switch优先级高。所以上述代码最后通过Switch显示了奶牛,但由于32行设置NodeMask为0,即不显示奶牛,因为NodeMask比Switch优先级高,所以奶牛最终不会显示。
  • 上述代码NodeMask和Switch节点都将同一个奶牛节点作为其孩子对象,即共享同一个奶牛孩子节点,类似C++中的浅拷贝。如果需要分别指向不同的奶牛节点,则应该像下面代码一样,分别挂接一个奶牛节点,类似C++的深拷贝,此时对各自奶牛的显示与隐藏互不影响:
// showOrHideNode.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<osgViewer/Viewer>
#include<osg/ArgumentParser>
#include<osgDB/readFile>
#include<osg/Group>
#include<osg/Switch>
#include<osg/PositionAttitudeTransform>
using namespace osg;
int main()
{
	auto spCowNode = osgDB::readRefNodeFile("cow.osg");
	if (nullptr == spCowNode)
	{
		osg::notify(osg::FATAL) << "cow node is null\r\n";
		return 1;
	}

	auto pGroup = new osg::Group();
	pGroup->addChild(spCowNode);

	osgViewer::Viewer viewer;
	auto pCamera = viewer.getCamera();
	auto defaultCullMask = pCamera->getCullMask();      // 相机默认的裁剪掩码
	auto defaultCowNodeMask = spCowNode->getNodeMask(); // 奶牛节点默认的掩码
	std::cout.setf(std::cout.hex, std::cout.basefield); // 以16进制输出掩码值
	std::cout.setf(std::cout.showbase);                 // 显示16进制前面的ox
	std::cout << "default Cull Mask of camera is : " << defaultCullMask << std::endl;
	std::cout << "default  Mask of cow node is : " << defaultCowNodeMask << std::endl;
	 pCamera->setCullMask(0x10); // 这里将相机裁剪掩码设置为0,即所有节点都被裁剪,不被渲染,此时视景器中的场景是空的,任何场景都不会绘制
	spCowNode->setNodeMask(0x01); 
	
	ref_ptr<osg::Switch> spSwitchNode = new osg::Switch();

	auto spCowNode2 = osgDB::readRefNodeFile("cow.osg");
	if (nullptr == spCowNode2)
	{
		osg::notify(osg::FATAL) << "cow node is null\r\n";
		return 1;
	}

	ref_ptr<osg::PositionAttitudeTransform> spPosNode = new osg::PositionAttitudeTransform;
	spPosNode->addChild(spCowNode2);
	spPosNode->setPosition(osg::Vec3d(10.0, 0.0, 0.0));
	spSwitchNode->addChild(spPosNode);
	spSwitchNode->setValue(0, true);
	pGroup->addChild(spSwitchNode);

	viewer.setSceneData(pGroup);
	return viewer.run();

}
 

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

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

相关文章

Java实现文件分片上传

文章目录 Java实现文件分片上传为什么要使用分片上传什么是分片上传&#xff1f;前后端代码 Java实现文件分片上传 为什么要使用分片上传 在需要上传文件时&#xff0c;不可避免地会遇到上传文件内容过大&#xff0c;上传时间太长地问题&#xff0c;采用文件分片上传就可以解…

ARM-M架构移植UCOS操作系统

最近准备面试&#xff0c;把本科到现在的一些比赛相关的东西整理一下。那些年在飞思卡尔在K60单片机上的UCOSII移植&#xff08;哎&#xff0c;心酸...&#xff09; 一、首先看下UCOSII的文件结构&#xff1a; 一些核心的文件解释&#xff1a; 【1、头文件】&#xff1a; inclu…

SQL多表查询常用语句总结

一、多表关系 &#xff08;一&#xff09;概述 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系&#xff0c;…

【MySQL】数据库中表的操作

表的操作 一、创建表 --- create table 表名(列名 类型 ...);1.1 创建表的案例 二、查看表2.1 查看选中数据库的所有表 --- show tables;2.2 查看&#xff08;描述&#xff09;表结构 --- desc 表名;2.3 查看建表信息 --- show create table 表名 \G 三、修改表 --- alter3.1 修…

说说我认为的AI和人类的未来

今天闲来无事&#xff0c;花了半天时间部署了一个Stable Diffusion的开源AI生成图片程序&#xff0c;因为电脑配置的原因&#xff0c;找了一个小模型集测试了一下效果&#xff0c;总的来说还是挺震惊的。上图是通过输入&#xff1a;长发美女森林漫步红色裙子 这三个关键词后花了…

useEffect的基础知识和底层机制

useEffect 是 React 中一个重要的 Hook&#xff0c;用来处理组件的副作用操作。它的基础知识包括两个方面&#xff1a;执行时机和参数。 执行时机&#xff1a; useEff ect 的执行时机包括两种情况&#xff1a; 组件挂载时&#xff0c;即第一次渲染之后。组件更新时&#xff…

pandas---Series与DataFrame索引、切片;多层索引、索引的堆叠

1. Series的索引和切片 1.1 Series的索引&#xff1a; 可以使用中括号取单个索引&#xff08;此时返回的是元素类型&#xff09;&#xff0c;或者中括号里一个列表取多个索引&#xff08;此时 返回的仍然是一个Series类型&#xff09;。分为显示索引和隐式索引&#xff1a; …

后台服务接口间大文件的流式发送和读取

文章目录 介绍代码设计代码参考客户端代码服务器端代码测试实例 介绍 使用HTTP协议进行数据流式传输是一种常见的方法。对于大文件数据传输可以使用HTTP的chunked编码或使用多部分响应来实现数据流式传输。 【HTTP的chunked编码】在发送数据的服务中&#xff0c;可以将数据切分…

postman接口测试学习笔记(非常详细)

目录 引言 1. 资源 2.接口测试 3. 接口返回数据和JSON详解 4.接口测试协议 5.企业接口测试的流程和方案 6. 接口测试工具以及Postman介绍 7.Postman之内置的动态参数和应用 8.接口关联 引言 接口测试工具如何选择&#xff1f;在我看来&#xff0c;Postman是一个非常值…

电商--红包活动总结

文章目录 背景表结构设计实现流程流程图流程解析流程优化 背景 这是一个来自于NFT电商项目&#xff0c;这是个营销策略的需求&#xff0c;为了快狠准&#xff0c;短期内刺激消费&#xff0c;拉动销售增加购买量。运营人员可以在平台创建红包&#xff0c;并且设置该红包的发放时…

Android系统视角下对APK的分析(1)- 静态分析APK文件

声明 以Android手机用户角度来看&#xff0c;安装各式各样的APP&#xff0c;基本就是从应用市场上 “搜索->下载->安装” 三连。而对Android系统来说&#xff0c;这就是个大工程了&#xff0c;因为对Android系统来说APK是“外来户”&#xff0c;如何安装它、有限制地支持…

【用户认证】密码加密,用户状态保存,cookie,session,token

相关概念 认证与授权 认证&#xff08;authentication &#xff09;是验证你的身份的过程&#xff0c;而授权&#xff08;authorization&#xff09;是验证你有权访问的过程 用户认证的逻辑 获取用户提交的用户名和密码根据用户名&#xff0c;查询数据库&#xff0c;获得完…

redis知识复习

redis知识复习 redis基础知识redis的认识一. 非关系型数据库 与 传统数据库 的区别二. 安装redis并设置自启动三. 熟悉命令行客户端四.熟悉图形化工具RDM redis的命令与数据结构一. 数据结构介绍二. redis通用命令&#xff08;熟练掌握&#xff09; redis的Java客户端一. Jedis…

文心一言 VS 讯飞星火 VS chatgpt (38)-- 算法导论5.4 2题

二、假设我们将球投入到b个箱子里&#xff0c;直到某个箱子中有两个球。每一次投掷都是独立的并且每个球落入任何箱子的机会均等。请问投球次数期望是多少? 文心一言&#xff1a; 这是一个典型的鸽巢原理&#xff08;Pigeonhole Principle&#xff09;问题。假设每次投球时&…

2023年上半年系统分析师下午真题及答案解析

试题一(25分) (试题一为必答题&#xff0c;试题二~五选答两题) 某软件公司拟开发一套汽车租赁系统&#xff0c;科学、安全和方便的管理租赁公司的各项业务&#xff0c;提高公司效率&#xff0c;提升利用率。注册用户在使用系统进行车辆预约时需执行以下操作&#xff1a;(a)用…

从0-1一起学习live555设计思想之二 RTSP交互过程

流媒体服务系列 文章目录 流媒体服务系列前言一、OPTION二、DESCRIBE三、SETUP四、PLAY总结前言 本篇文章通过代码去分析rtsp交互过程与工作原理。由于live555的继承关系太过复杂,所以做了个图简单记录一下与h264文件传输相关的类继承关系。 一、OPTION OPTION比较简单,就…

【调制BFSK】二进制频移键控FSK的数字调制(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

ARM学习(22)断点认识以及调试

笔者来聊聊断点以及断点的调试 1、断点原理 断电的原理一般分为两种&#xff0c;插入断点指令或者利用硬件调试寄存器进行断点。 前者程序如果在RAM&#xff08;SRAM、DDR&#xff09;上&#xff0c;则调试器可以直接在断点地址处插入断点指令&#xff0c;例如BKPT&#xff0…

python自动化测试-自动化基本技术原理

1 概述 在之前的文章里面提到过&#xff1a;做自动化的首要本领就是要会 透过现象看本质 &#xff0c;落实到实际的IT工作中就是 透过界面看数据。 掌握上面的这样的本领可不是容易的事情&#xff0c;必须要有扎实的计算机理论基础&#xff0c;才能看到深层次的本质东西。 …