OSG开发笔记(三十九):OSG中模型的透明度实现、球体透明度Demo
前言
在OSG中,对于一些效果未被选中或者包含等业务,需要半透明效果来实现。
本篇描述OSG的半透明实现方式。
Demo
透明
功能概述
透明效果在三维场景中扮演着重要角色,它能够模拟玻璃、水体、烟雾等自然现象,增加场景的层次感和真实感。然而,透明效果的实现并非易事,它涉及到复杂的渲染技术和算法。OSG作为一个功能强大的场景图库,为透明效果的实现提供了强有力的支持。
材质属性的调整
在OSG中,实现透明效果的第一步是调整材质属性。材质属性决定了物体表面的外观特性,包括颜色、光泽度、反射率和透明度等。要实现透明效果,需要设置材质的透明度属性。
OSG中的osg::Material类用于设置物体的材质属性。通过调整osg::Material::TRANSPARENCY属性,我们可以控制物体的透明度。同时,我们还需要设置物体的颜色属性,并指定颜色的RGBA分量,其中A分量表示透明度。
深度测试的设置
深度测试是三维渲染中的一项重要技术,它用于确定物体在场景中的前后关系。在实现透明效果时,深度测试的设置尤为关键。需要确保深度测试是开启的,以便正确处理透明物体与背景或其他物体的遮挡关系。然而,由于透明物体具有部分遮挡的特性,还需要考虑深度写入(GL_DEPTH_WRITEMASK)的设置。在某些情况下,关闭深度写入可以避免透明物体渲染时的深度冲突问题。
渲染顺序的控制
透明物体的渲染顺序对其最终呈现效果具有重要影响。为了获得正确的渲染效果,我们需要确保透明物体按照从远到近的顺序进行渲染。OSG提供了透明排序机制来帮助我们实现这一目标。
通过设置osg::StateSet::TRANSPARENT_BIN渲染提示,我们可以将透明物体添加到单独的渲染队列中。OSG将按照从远到近的顺序渲染这些物体,从而确保渲染结果的正确性。
混合模式的应用
混合模式是实现透明效果的关键技术之一。它决定了透明物体与背景或其他物体混合时的颜色计算方式。在OSG中,我们可以通过设置osg::BlendFunc属性来指定混合模式。
常见的混合模式包括源颜色与目的颜色的加权和、源颜色与目的颜色的差值等。通过选择合适的混合模式,我们可以获得不同的透明效果。例如,使用GL_SRC_ALPHA和GL_ONE_MINUS_SRC_ALPHA作为混合因子,可以实现标准的透明度混合效果。
在OpenSceneGraph(OSG)中,实现透明效果通常涉及调整材质属性、深度测试设置以及渲染顺序。
要设置对象透明,是通过调整材质的透明度属性。osg::Material 类用于设置对象的材质属性,其中 osg::Material::TRANSPARENCY属性可以用于设置透明度。
基本实现流程
- 创建材质实例,通过材质实现的(不是常规思维RGBA,因为A在此无效)
- 材质实例设置材质颜色,材质颜色只有RGB有效,A无效
- 设置材质实例的透明度
- 获取模型(需要透明)的模型状态集
- 状态集开启模型的深度测试
- 状态集设置透明通道单独渲染
- 状态集设置混合设置模式
注意事项
- 确保透明对象在渲染队列中的顺序是正确的。OSG的透明排序机制可以帮助处理这个问题,但在某些复杂场景中,你可能需要手动控制渲染顺序。
- 深度写入(GL_DEPTH_WRITEMASK)和深度测试(GL_DEPTH_TEST)的设置会影响透明对象的渲染效果。
- 混合模式(osg::BlendFunc)的设置会影响透明对象与背景或其他对象的混合方式。
通过上述步骤,应该能够在OpenSceneGraph中实现基本的透明效果。如果需要更高级的透明处理,可以进一步探索OSG的渲染队列和混合模式设置。
透明实现步骤
步骤一:获取状态集
// 步骤一:获取状态集
osg::ref_ptr<osg::StateSet> pStateSet = pNode->getOrCreateStateSet();
步骤二:开启深度测试
// 步骤二:状态集 设置深度测试开启,确保透明的物体深度测试开启
pStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
步骤三:创建材质实例
// 步骤三:创建材质实例
osg::ref_ptr<osg::Material> pMaterial = new osg::Material;
步骤四:设置材质颜色(理论上这的a无效)
// 步骤四:材质实例 设置材质颜色(RGB部分),透明度在颜色数组中设置
pMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(color.x, color.y, color.z, color.a));
步骤五:设置材质透明度(理论上由这里控制透明度)
// 步骤五:材质实例 设置透明度(0-255): 设置了反倒没图形了
pMaterial->setTransparency(osg::Material::FRONT_AND_BACK, color.a * 255.0);
// pMaterial->setTransparency(osg::Material::FRONT_AND_BACK, 255.0);
步骤六:设置材质
// 步骤六:状态集 设置材质
pStateSet->setAttributeAndModes(pMaterial.get());
步骤七:设置透明通道单独渲染
// 步骤七:状态集 设置透明通道单独渲染
pStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
步骤八:设置渲染混合模式
// 步骤八:状态集 设置渲染混合模式
pStateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
Demo源码
OsgManager.cpp相关函数代码
osg::ref_ptr<osg::Geode> OsgManager::createSphere(Point3F center, double radius, double ratio)
{
// 绘制球体
// 步骤一:创建一个用户保存几何信息的对象osg::Geode
osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;
// 步骤二:创建专门指明精细度的类osg::TessellationHints,并设置对应精细度
osg::ref_ptr<osg::TessellationHints> pHints = new osg::TessellationHints;
pHints->setDetailRatio(ratio);
// 步骤三:绘制几何类型(几何体)
pGeode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(center.x, center.y, center.y), radius), pHints));
return pGeode.get();
}
osg::ref_ptr<osg::Material> OsgManager::setTransparency(osg::Node *pNode, Point4F color)
{
#if 1
// 设置透明度
// 步骤一:获取状态集
osg::ref_ptr<osg::StateSet> pStateSet = pNode->getOrCreateStateSet();
// 步骤二:状态集 设置深度测试开启,确保透明的物体深度测试开启
pStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
// 步骤三:创建材质实例
osg::ref_ptr<osg::Material> pMaterial = new osg::Material;
// 步骤四:材质实例 设置材质颜色(RGB部分),透明度在颜色数组中设置
pMaterial->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(color.x, color.y, color.z, color.a));
// 步骤五:材质实例 设置透明度(0-255): 设置了反倒没图形了
// pMaterial->setTransparency(osg::Material::FRONT_AND_BACK, color.a * 255.0);
// pMaterial->setTransparency(osg::Material::FRONT_AND_BACK, 255.0);
// 步骤六:状态集 设置材质
pStateSet->setAttributeAndModes(pMaterial.get());
// 步骤七:状态集 设置透明通道单独渲染
pStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
// 步骤八:状态集 设置渲染混合模式
pStateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
// static int z = 0;
// pStateSet->setRenderBinDetails(z++,QString("RenderBin%1").arg(z).toStdString());
#else
osg::ref_ptr<osg::Material> pMaterial = new osg::Material;
// Alpha混合开启
osg::ref_ptr<osg::StateSet> pStateSet = pNode->getOrCreateStateSet();
//取消深度测试
pStateSet->setMode(GL_BLEND,osg::StateAttribute::ON);
pStateSet->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
pStateSet->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
pStateSet->setRenderBinDetails(11, "RenderBin");
#endif
return pMaterial.get();
}
OsgWidget.cpp
osg::ref_ptr<osg::Node> OsgWidget::getTransparency()
{
// 其他demo的控件
updateControlVisible(false);
osg::ref_ptr<osg::Group> pGroup = new osg::Group();
{
// 创建几何体
osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSphere(Point3F(0, 0, 0), 0.5);
// 设置透明度
osg::ref_ptr<osg::Material> pMaterial = OsgManager::setTransparency(pGeode, Point4F(1.0, 1.0, 1.0, 0.8));
pGroup->addChild(pGeode);
}
#if 0
{
// 创建几何体
osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSphere(Point3F(-1, 0, 0), 0.5);
// 设置透明度
osg::ref_ptr<osg::Material> pMaterial = OsgManager::setTransparency(pGeode, Point4F(1.0, 0.0, 0.0, 0.25));
pGroup->addChild(pGeode);
}
{
// 创建几何体
osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSphere(Point3F(1, 0, 0), 0.5);
// 设置透明度
osg::ref_ptr<osg::Material> pMaterial = OsgManager::setTransparency(pGeode, Point4F(0.0, 1.0, 0.0, 0.25));
pGroup->addChild(pGeode);
}
{
// 创建几何体
osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSphere(Point3F(0, -1, 0), 0.5);
// 设置透明度
osg::ref_ptr<osg::Material> pMaterial = OsgManager::setTransparency(pGeode, Point4F(0.0, 0.0, 1.0, 0.50));
pGroup->addChild(pGeode);
}
{
// 创建几何体
osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSphere(Point3F(0, 1, 0), 0.5);
// 设置透明度
osg::ref_ptr<osg::Material> pMaterial = OsgManager::setTransparency(pGeode, Point4F(1.0, 1.0, 0.0, 0.50));
pGroup->addChild(pGeode);
}
#endif
{
// 创建几何体
osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSphere(Point3F(0, 0, -1), 0.5);
// 设置透明度
osg::ref_ptr<osg::Material> pMaterial = OsgManager::setTransparency(pGeode, Point4F(1.0, 0.0, 1.0, 0.5));
pGroup->addChild(pGeode);
}
{
// 创建几何体
osg::ref_ptr<osg::Geode> pGeode = OsgManager::createSphere(Point3F(0, 0, 1), 0.5);
// 设置透明度
osg::ref_ptr<osg::Material> pMaterial = OsgManager::setTransparency(pGeode, Point4F(0.0, 1.0, 1.0, 0.5));
pGroup->addChild(pGeode);
}
// 开启深度测试
// OsgManager::setDepthTest(pGroup, true);
// 关闭光照
// OsgManager::setLighting(pGroup.get(), false);
return pGroup.get();
}
工程模板v1.39.0
入坑
入坑一:设置透明后不显示
问题
设置透明后不显示
尝试
去掉透明度设置后,可以显示:
设置后就不显示,检查代码设置流程,并没有发现问题,然后查看了Demo代码,半透明也不显示;
到现在为止,笔者osg3.4.0的ming32版本种,旋转中心和半透明都有问题。
然后继续测试,发现设置透明度没用,但是设置透明颜色可以:
解决
入坑二:出现渲染截面
问题
出现渲染截面,测试只有球体、球面的时候才出现。
换个颜色:
原理
这是深度测试问题,单独开了每一个的深度测试,需要开这几个模型进行深度测试,开了深度测试也是一样,检查总代码是开了的,尝试下关闭所有深度测试,启动就有问题(开启深度测试,至少启动没有问题):
开启深度测试,关闭光照:
再次尝试打开stl球体模型,也是不行的,效果跟上面的一样,下面是绘制的stl球体:
解决
未解决,准备更换版本测试,经过多个版本都是一样。
OSG开发笔记(三十九):OSG中模型的透明度实现、球体透明度Demo的更多相关文章
- Android UI开发第三十九篇——Tab界面实现汇总及比较
Tab布局是iOS的经典布局,Android应用中也有大量应用,前面也写过Android中TAb的实现,<Android UI开发第十八篇——ActivityGroup实现tab功能>.这 ...
- .Net开发笔记(十九) 创建一个可以可视化设计的对象
阅读本篇博客之前需要了解VS窗体设计器的工作原理,详细可参见本系列博客(十).(十一).(十二).必须需要知道的一条结论就是:处于窗体设计器(Form Designer)中的任何组件(包含控件,下同) ...
- BizTalk 开发系列(三十九) BizTalk Server 2009技术概览
BizTalk Server 2009已经发布一段时间了,之前Beta版发布的时候也写过一篇文章<BizTalk Server 2009 Beta初体验>, 当时比较了2006 R2与20 ...
- 【Unity 3D】学习笔记三十九:控制组件
控制组件 角色控制组件和刚体组件都具备物理引擎的功能,须要绑定游戏对象才干实现对应的物理效果,而且同一个游戏对象中两者仅仅能存在一个,不能共存.刚体组件能够很精确的模拟现实世界中的一切物理效果,而角色 ...
- 网站开发进阶(三十四)编码中的setCharacterEncoding 理解
编码中的setCharacterEncoding 理解 1.pageEncoding="UTF-8"的作用是设置JSP编译成Servlet时使用的编码. 2.contentType ...
- Java开发笔记(十九)规律变化的for循环
前面介绍while循环时,有个名叫year的整型变量频繁出现,并且它是控制循环进出的关键要素.不管哪一种while写法,都存在三处与year有关的操作,分别是“year = 0”.“year<l ...
- 论文阅读笔记三十九:Accurate Single Stage Detector Using Recurrent Rolling Convolution(RRC CVPR2017)
论文源址:https://arxiv.org/abs/1704.05776 开源代码:https://github.com/xiaohaoChen/rrc_detection 摘要 大多数目标检测及定 ...
- tensorflow学习笔记(三十九):双向rnn
tensorflow 双向 rnn 如何在tensorflow中实现双向rnn 单层双向rnn 单层双向rnn (cs224d) tensorflow中已经提供了双向rnn的接口,它就是tf.nn.b ...
- Java开发学习(三十九)----SpringBoot整合mybatis
一.回顾Spring整合Mybatis Spring 整合 Mybatis 需要定义很多配置类 SpringConfig 配置类 导入 JdbcConfig 配置类 导入 MybatisConfig ...
- 安卓开发笔记(十九):异步消息处理机制实现更新软件UI
主界面代码 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:andr ...
随机推荐
- 实战合集 | I/O 2021 Flutter 研讨会
2021 年的 Google I/O 大会已圆满闭幕,本次大会带来了诸多关于各项谷歌开发技术产品的最新更新.在此次 I/O,Flutter 发布了 2.2 版本,包括 Web 版的增强.更多 Mate ...
- HarmonyOS NEXT 底部选项卡功能
在HarmonyOS NEXT中使用ArkTS实现一个完整的底部选项卡功能,可以通过以下几个步骤来完成: 创建Tabs组件:使用Tabs组件来创建底部导航栏,并通过barPosition属性设置其位置 ...
- 高通dump ftrace & kernelshark使用
简介 高通 ramdump 可以解析出 ftrace,方便用于追踪 快省稳 问题. kernelshark 是一个可以查看 trace event 的图形化工具,方便梳理和观察内核微观行为. trac ...
- 墨天轮国产数据库沙龙 | 张晓庆:GoldenDB分布式数据库的自动安装与备份恢复
在共同推进国产化生态发展的进程下,墨天轮正式推出"墨天轮国产数据库沙龙"系列直播活动,将定期邀请各国产数据库产品专家.掌门人,共同探讨如何达成技术"自主可控"的 ...
- C#的排序方法 OrderBy
using System;using System.Collections.Generic;using System.Linq;using System.Net.Http;using System.R ...
- Vue中mixins(混入)的介绍和使用
为什么引进 mixins 随着项目的开发,组件越来越多 ,这就导致了在各个组件中需要编写功能相同的代码段,重复地定义这些相同的属性和方法,导致代码地冗余,还不利于后期代码的维护 混入mixins 的创 ...
- 探索 Kubernetes 持久化存储之 Longhorn 初窥门径
作者:运维有术星主 在 Kubernetes 生态系统中,持久化存储扮演着至关重要的角色,它是支撑业务应用稳定运行的基石.对于那些选择自建 Kubernetes 集群的运维架构师而言,选择合适的后端持 ...
- 使用 KubeSphere 应用商店 5 分钟内快速部署 JuiceFS
作者:朱唯唯,尹珉 JuiceFS 简介 JuiceFS 是为海量数据设计的分布式文件系统,使用对象存储来做数据持久化,避免重复造轮子,还能大大降低工程复杂度,让用户专注解决元数据和访问协议部分的难题 ...
- KubeSphere v4 安装指南
日前,KubeSphere v4 发布,相较于之前的版本,新版本在架构上有了颠覆性的变化.为了让社区的各位小伙伴能够丝滑的从旧版本过渡到新版本,我们特别推出本篇安装指南文章,以供参考. 关于 Kube ...
- Redhat 7安装Oracle 11.2.0.4 RAC 数据库软件中报错:Error in invoking target 'agent nmhs' of makefile
环境:Redhat Linux 7.6 + Oracle 11.2.0.4 RAC 现象:图像化安装数据库软件过程中的86%时,报错. 1. 具体现象 2. 定位问题 3. 解决问题 1. 具体现象 ...