查看: 3164|回复: 4

关于HUD和渲染到纹理之间的冲突

[复制链接]

该用户从未签到

发表于 2011-1-11 17:44:02 | 显示全部楼层 |阅读模式
我现在遇到了一个麻烦事:
1、我希望将场景渲染到一个图片上去,那么显然我需要使用一个PreRender方式的Camera。
2、我的场景中包含有天空球和指北针之类的HUD对象,这些东西又是PostRender的。

冲突:
将场景渲染到图片上去,PreRender的相机肯定先渲染,此时,所有的HUD都是PostRender的,它们还没有来得及渲染出来。因此,得到的图片上面不包含HUD对象,怎么办呢?有谁遇到过这种问题?

莫非要将所有的HUD都改为使用Projection节点来实现?而这样能否满足要求都是个问题,有些HUD对象(比如我的场景天空球),不一定能够使用Projection节点实现的。

该用户从未签到

发表于 2011-1-13 09:09:34 | 显示全部楼层
严格来说RTT和HUD应该是可以协同工作的,按照Camera与RenderStage的关系,PostRender的HUD相机应该属于PreRender相机的子节点,那么RenderStage也是父子关系,因此渲染时应当是按照下面的逻辑:“首先渲染RTT相机下的场景,而HUD的内容属于这个子场景中最后渲染的”

不过我做了简单的实验,貌似这样的确不能显示HUD的文字,我想调试一下osg的源代码也许可以发现问题的所在,不过您也不妨先用上下面的代码来实现HUD相机:
  1. camera->setRenderOrder( osg::Camera::NESTED_RENDER );
  2. camera->getOrCreateStateSet()->setRenderBinDetails( 999, "RenderBin" );
  3. camera->getOrCreateStateSet()->setAttribute( new osg::Depth(osg::Depth::ALWAYS) );
复制代码

该用户从未签到

 楼主| 发表于 2011-1-13 11:45:35 | 显示全部楼层
本帖最后由 yin_savage 于 2011-1-13 11:47 编辑

camera->setRenderOrder( osg::Camera::NESTED_RENDER );
NESTED_RENDER方式,我还是第一次看到,呵呵,惭愧惭愧。

对相机使用深度缓存,我通常也是少用,可能没有用过。不过可以想象这肯定是可以用的。一般做HUD,不论是“总在最后”的天空背景,还是“总在最前”的指北针之类的东西,我都是直接使用相机节点,给它一个Ortho2D的投影矩阵,也很难被场景中其他的物体挡住。不过我觉得你使用深度缓存可能更可靠一些。

而关于RenderBinDetails,说来惭愧,我从来没有用过。需要加强学习。

目前这个问题给我带来的打击比较巨大,会直接拦住我的一个需求,所以我当然的会对你的建议无条件采纳。至少是先试了再说。

这里,我可以简单描述一下我的需求:
客户需要对3D场景调色(类似彩色电视机的饱和度、亮度、对比度的调整一样),权衡之下,我使用了GLSL来实现该功能。整体思路是,将原有的场景,全部渲染到一个纹理位图上去,然后,OSG的视图仅仅只将该纹理位图贴到一个板子上(我称为ScreenBoard),将ScreenBoard以Ortho2D方式渲染到屏幕。GLSL的代码,仅仅只是对ScreenBoard进行处理。我这种思路,可以避免GLSL代码里面对光照、阴影、雾效等等一切不可预料的渲染属性进行遍历。要将原有场景渲染到纹理位图上去,我选择的就是Camera节点,PreRender方式。这下场景调色的功能是完美地实现了,我原有场景里面的指北针、天空球、状态条、文字等一切使用了HUD相机的东西,全部都没了,它们无法渲染到纹理位图上去。我目前的猜测是,渲染顺序方面发生了不可协调的矛盾。

若实在不可协调,那么也许我会使出损招,直接将视图的主相机定向到纹理,得到的纹理位图,直接使用WindowsGDI的方式贴到窗口上去。也许这样就能够避开这种矛盾。

该用户从未签到

发表于 2011-1-13 13:27:27 | 显示全部楼层
我仔细地学习了osg的相关源代码,现在这个问题我已经完全明白了,不过我不认为这是一个问题,或者说这是一个很难取舍的事情。

“首先渲染RTT相机下的场景,而HUD的内容属于这个子场景中最后渲染的”,这一点可以证明是完全无误地执行了的,问题在于RTT动作执行的时机。RenderToTexture(FB,PB,FBO等具体实现方法是类似的)分为两个步骤,第一步是bindTexture,然后渲染实际场景,最后copyToTexture——而drawPostRenderStages的步骤在copyToTexture之后,因此无论如何也不会提前执行到它。这样保证了当前渲染和PostRender两个步骤是完全分离的;当然也因此断绝了您想要把PostCamera渲染到纹理的希望。

NESTED_RENDER的方案保证子相机不会被放置在Pre或者PostRender的队列中,而RenderBinDetails事实上是控制渲染顺序的利器。数值越大,渲染的顺序越靠后(默认为0,也可以为负),这里的999只是一个示意而已。事实上我们使用HUDCamera的目的就是保证这些对象(屏显文字,指南针,天空盒等)在渲染完其它场景之后渲染,因此合理使用RenderBinDetails也就完全满足Post-Processing(也就是您的ScreenBoard,不过我的说法是通用的)的要求。

当然即使您不愿意这么做,也不必想什么“损招”,我们还有很多变通的方法,最简单的就是使用Camera:: DrawCallback()来替代attach(),在InitialDrawCallback中绑定一个FBO对象,然后在FinalDrawCallback中拷贝到纹理,这样就可以为一个普通的Camera实现RTT的要求,而且这时我们可以将PostRender的子对象也包含在内!ScreenCaptureHandler就采用了这样的做法

该用户从未签到

发表于 2011-1-14 15:53:01 | 显示全部楼层
学习学习~~
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表