Graphics OpenSceneGraph:Don';t在绘制半透明对象时更新z缓冲区 问题:

Graphics OpenSceneGraph:Don';t在绘制半透明对象时更新z缓冲区 问题:,graphics,rendering,transparency,openscenegraph,Graphics,Rendering,Transparency,Openscenegraph,在绘制半透明对象时,是否可以告诉OpenSceneGraph使用Z缓冲区,但不更新它 动机 在绘制半透明对象时,它们的绘制顺序很重要,因为如果以错误的顺序绘制,应该可见的曲面可能会被遮挡。在某些情况下,OpenSceneGraph自己关于对象绘制顺序的直觉会导致半透明曲面被其他半透明曲面遮挡,并可能出现“弹出”(如果该词可以用这种方式使用的话),当OSG认为对象中心到摄影机的距离顺序已更改并决定更改渲染顺序时。因此,有必要通过使用状态集上的setRenderBinDetails方法手动指定每个对

在绘制半透明对象时,是否可以告诉OpenSceneGraph使用Z缓冲区,但不更新它

动机 在绘制半透明对象时,它们的绘制顺序很重要,因为如果以错误的顺序绘制,应该可见的曲面可能会被遮挡。在某些情况下,OpenSceneGraph自己关于对象绘制顺序的直觉会导致半透明曲面被其他半透明曲面遮挡,并可能出现“弹出”(如果该词可以用这种方式使用的话),当OSG认为对象中心到摄影机的距离顺序已更改并决定更改渲染顺序时。因此,有必要通过使用状态集上的
setRenderBinDetails
方法手动指定每个对象的渲染箱来手动控制半透明对象的渲染顺序

但是,这也可能并不总是有效,因为在一般情况下,不可能为对象选择渲染顺序(即使场景中的各个三角形已排序),以便正确绘制所有碎片(请参见,例如),并且仍然可能会发生遮挡。另一种选择是使用或其他方法,但坦率地说,我不知道在OpenSceneGraph中实现这一点有多困难,也不知道这会使应用程序的速度降低多少


在我的例子中,作为审美与算法复杂度和速度之间的权衡,理想情况下,我总是想画一个半透明表面的碎片,即使(在该像素中)更接近相机的另一个半透明表面的碎片已经画出来了。这将防止半透明表面被其他半透明表面弹出和遮挡,并且如果对于渲染的每个半透明对象,Z缓冲区用于测试可见性,但在绘制碎片时未更新,则可以有效地实现这一点。

您完全正确

是的,可以保持Z-test处于启用状态,但可以在绘图期间使用
setWriteMask()
关闭Z-write:

// Disable Z-writes
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
depth->setWriteMask(false);
myNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON)

// Enable Z-test (needs to be done after Z-writes are disabled, since the latter
// also seems to disable the Z-test)
myNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
//禁用Z写入
osg::ref_ptr depth=新osg::depth;
深度->设置写任务(假);
myNode->getOrCreateStateSet()->setAttributeAndModes(深度,osg::StateAttribute::ON)
//启用Z-test(需要在禁用Z-write后执行,因为后者
//也似乎禁用了Z测试)
myNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST,osg::StateAttribute::ON);

您可能希望查看几年前我们为CAD客户端编写的OSGTTransparencyTool nodekit:

它包括几种透明度方法,您可以使用场景测试这些方法并检查其源实现,包括顺序无关的透明度深度剥离实现和受Open Inventor启发的延迟混合方法。延迟混合是一种高性能的单程未排序近似,如果绝对透明度精度不是最重要的标准,它可能会检查您想要的所有框

如果你还没有读过,这里有一篇文章详细讨论了各种方法:

你完全在正确的轨道上

是的,可以保持Z-test处于启用状态,但可以在绘图期间使用
setWriteMask()
关闭Z-write:

// Disable Z-writes
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
depth->setWriteMask(false);
myNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON)

// Enable Z-test (needs to be done after Z-writes are disabled, since the latter
// also seems to disable the Z-test)
myNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
//禁用Z写入
osg::ref_ptr depth=新osg::depth;
深度->设置写任务(假);
myNode->getOrCreateStateSet()->setAttributeAndModes(深度,osg::StateAttribute::ON)
//启用Z-test(需要在禁用Z-write后执行,因为后者
//也似乎禁用了Z测试)
myNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST,osg::StateAttribute::ON);

您可能希望查看几年前我们为CAD客户端编写的OSGTTransparencyTool nodekit:

它包括几种透明度方法,您可以使用场景测试这些方法并检查其源实现,包括顺序无关的透明度深度剥离实现和受Open Inventor启发的延迟混合方法。延迟混合是一种高性能的单程未排序近似,如果绝对透明度精度不是最重要的标准,它可能会检查您想要的所有框

如果你还没有读过,这里有一篇文章详细讨论了各种方法:

Hm,据报道,“延迟混合”似乎正是我所描述的。通过
depth->setWriteMask(false)
,我猜您指的是
osg::depth
类中的方法,但是如何获得
osg::depth
对象?@hellogoodbay您可以创建一个新的osg::depth对象并将其作为myNode->getOrCreateStateSet()->setAttributeAndModes(depth,osg::StateAttribute::ON)附加到状态集;嗯,根据这篇文章,似乎“延迟混合”正是我所描述的。通过
depth->setWriteMask(false)
,我猜您指的是
osg::depth
类中的方法,但是如何获得
osg::depth
对象?@hellogoodbay您可以创建一个新的osg::depth对象并将其作为myNode->getOrCreateStateSet()->setAttributeAndModes(depth,osg::StateAttribute::ON)附加到状态集;