查看: 3820|回复: 22

屏幕截图的问题

[复制链接]

该用户从未签到

发表于 2010-12-3 11:44:55 | 显示全部楼层 |阅读模式
我做了一个RTT过程:
osg::ref_ptr<osg::GraphicsContext::Traits> pTraits = new osg::GraphicsContext::Traits;
pTraits->x     = 0;
pTraits->y     = 0;
pTraits->width    = 800;
pTraits->height    = 600;
pTraits->windowDecoration = false;
pTraits->doubleBuffer  = true;
pTraits->sharedContext  = 0;
pTraits->pbuffer   = true;
pTraits->inheritedWindowData = NULL;
osg::ref_ptr<osg::GraphicsContext> pGraphicsContext = osg::GraphicsContext::createGraphicsContext(pTraits.get());
pGraphicsContext->realize();

osg::ref_ptr<osg::Camera> pSlaveCamera = new osg::Camera;
pSlaveCamera->setName(“My Slave Camera”);
pSlaveCamera->setGraphicsContext(pGraphicsContext.get());
pSlaveCamera->setViewport(new osg::Viewport(0, 0, 800, 600));

m_pBufferImage = new osg::Image;
m_pBufferImage->setName("My Buffer Image");
m_pBufferImage->allocateImage(800, 600, 1, GL_BGRA, GL_UNSIGNED_BYTE);
pSlaveCamera->attach(osg::Camera::COLOR_BUFFER, m_pBufferImage.get());
pSlaveCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
osg::ref_ptr<FetchingSignal> pSignal = new FetchingSignal(this);
pSlaveCamera->setFinalDrawCallback(pSignal.get());    // 在这个回调里面将图片保存到文件,使用osgDB::writeImageFile
const GLenum eBuffer = pTraits->doubleBuffer ? GL_BACK : GL_FRONT;
pSlaveCamera->setDrawBuffer(eBuffer);
pSlaveCamera->setReadBuffer(eBuffer);
m_pTargetView->addSlave(pSlaveCamera, osg::Matrix(), osg::Matrix(), true);

企图通过Slave相机在后台截图,并存储到文件。
现在遇到一个麻烦:
1、osg报出错误信息:
RenderStage::runCameraSetUp(), FBO setup failed, FBO status= 0x8cd6
Warning: detected OpenGL error 'invalid enumerant' at end of SceneView::draw()
这些出错的位置我全部用断点拦下来,可惜看不出是什么原因导致的错误,因此目前还没有纠正。

2、若我主场景的根节点中包含PageLOD的节点,那么保存出来的图片中都看不到纹理,建筑都是白色的。光影效果都存在,就建筑的纹理都不见了。若场景中没有PageLOD节点,比如就仅仅只是osg的那条奶牛,那么尽管上面提到有osg的报错信息,但是还是能够完整无误的生成图片。

哪位能够给我个建议啊?

该用户从未签到

 楼主| 发表于 2010-12-3 12:05:58 | 显示全部楼层
其实我还有一点不明白的是,使用Slave相机和使用PreDraw的RTT相机,到底有什么区别呢?

该用户从未签到

 楼主| 发表于 2010-12-3 16:01:21 | 显示全部楼层
自己顶一个。
有这方面经验的,帮个忙哈,我现在拦在这里没办法了

该用户从未签到

发表于 2010-12-3 16:10:41 | 显示全部楼层
本帖最后由 aya_daxiang 于 2010-12-3 16:33 编辑

编辑下:

我之前以为第一个问题是出在:
  1. m_pBufferImage->allocateImage(800, 600, 1, GL_BGRA,
  2. GL_UNSIGNED_BYTE);
复制代码
这里,但现在发现好象这里没有问题。不好意思了。

该用户从未签到

 楼主| 发表于 2010-12-3 18:03:20 | 显示全部楼层
RenderStage::runCameraSetUp(), FBO setup failed, FBO status= 0x8cd6
Warning: detected OpenGL error 'invalid enumerant' at end of SceneView::draw()

上面的是osg的报错信息。我弃用FBO,关于FBO的错误提示就没有了。但是OpenGL的'invalid enumerant' 错误还是一直存在的。但是可以肯定是,我的模型是没有问题的,它能够正常的在主相机中渲染出来,为什么到了SlaveCamera中,它就渲染不出纹理了呢?

该用户从未签到

 楼主| 发表于 2010-12-3 22:43:27 | 显示全部楼层
拜求,有人能够跟我找出问题所在么?

该用户从未签到

发表于 2010-12-6 10:08:37 | 显示全部楼层
FBO的错误可能与您的显卡对FBO的支持有关
至于invalid enumerant的错误,这恐怕与您在FetchingSignal中的实现有关

事实上既然您已经把image给attach到相机上,那么完全可以在任何更新回调中把图像保存出来。

若我主场景的根节点中包含PageLOD的节点,那么保存出来的图片中都看不到纹理,建筑都是白色的。光影效果都存在,就建筑的纹理都不见了。若场景中没有PageLOD节点,比如就仅仅只是osg的那条奶牛,那么尽管上面提到有osg的报错信息,但是还是能够完整无误的生成图片。
我更倾向于这与您的显卡支持有关。

我曾经提交过一个osgposter例子,就是专门输出超高分辨率截图图片,可以处理pagedlod数据,您可以参考

该用户从未签到

 楼主| 发表于 2010-12-7 09:54:08 | 显示全部楼层
这是我的FetchingSignal里面的全部源代码:
void LargeImageFetcher::FetchingSignal:perator()(const osg::Camera &camera) const
{
if(m_pFetcher->getFetchingStatus() != LargeImageFetcher::FS_CMD_SENDED)
{
  return;
}
const std::string &strCameraName = camera.getName();
if(strCameraName != LargeImageFetcher::m_strSlaveCameraID)
{
  return;
}
m_pFetcher->setFetchingStatus(LargeImageFetcher::FS_IMG_ALREADY);
return;
}


还有一部分:
void LargeImageFetcher::setFetchingStatus(LargeImageFetcher::FetchingStatus eStatus)
{
OpenThreads::ScopedLock<OpenThreads::Mutex>  scope(m_mutexStatusLocker);
m_eFetchingStatus = eStatus;
}

该用户从未签到

 楼主| 发表于 2010-12-7 10:42:42 | 显示全部楼层
我现在怀疑是我使用了osg::View::addSlave来挂接截图相机所导致。我仔细对比过我的程序和Array的osgPoster程序,其实最根本的差别就在于我使用的是Slave相机,而Array使用的是PreRender相机。这里我再花时间来改一下试试看。

至于前面的OpenGL错误‘invalid enumerant’,显得有些无厘头,我没有增加任何非法的StateSet,甚至根本就没有调整过任何StateSet,不可能由于我的失误导致OpenGL枚举量非法。
FBO的错误可以理解,显卡不支持。

当然,我的程序和osgPoster还是有区别的。比如我每渲染一张子图,则立即将子图存盘,释放掉相关相机和图片,然后重新设置相机渲染下一张子图,但这显然不是导致问题的原因。
我的客户要求能够渲染出任何大小的图片(1000亿像素的图片都是有可能的),我绝对不能将所有的子图都放在内存中,等着最后一次性拼接。若是只需要渲染出1亿像素的图片,我完全可以直接用一个相机,一次性大图渲染,根本犯不着后期拼图的问题。

该用户从未签到

发表于 2010-12-7 12:43:02 | 显示全部楼层
addSlave来挂接截图相机所导致
这或许有些相当多余,您的RTT相机不是pre render的??

不可能由于我的失误导致OpenGL枚举量非法。
这么说并不能解决什么问题,如果您的程序中什么都没做的话,我想自然也不会有这样的错误发生

我绝对不能将所有的子图都放在内存中,等着最后一次性拼接
这一点osgposter也可以做到,您可以看一下其中的代码

该用户从未签到

发表于 2010-12-7 14:09:10 | 显示全部楼层
RTT相机不是pre的,那截图不是很混乱

该用户从未签到

 楼主| 发表于 2010-12-8 14:12:14 | 显示全部楼层
本帖最后由 yin_savage 于 2010-12-8 14:13 编辑

回Array:
1、我的相机的确不是PreRender的。我就是先自行创建一个GraphicsContext,然后依此来创建一个相机。然后将该相机作为Slave相机添加到了视图里面(osg::View::addSlave方法)。关于添加此相机的完全代码,如本帖一楼。
2、我的整个程序都没有修改StateSet。仅仅只是使用语句
m_pTargetView->addSlave(pSlaveCamera, osg::Matrix(), osg::Matrix(), true);
来添加了一个相机而已。为什么要出现OpenGL的枚举量错误,实在难以理解。而且跟踪代码,发现场景主相机在做RenderTraverals时,该错误是不会出现的。而对SlaveCamera做RenderTraverals时,控制台窗口就出现了该提示。显得十分无厘头。
3、osgPosger是不能输出800000*600000的图片的,哪怕再缩小10倍,80000*60000,也是不行的。若这样试验一下,程序一定会崩溃在new语句上面。我说过,我的程序输出图片的大小不能限制于内存空间,只能限制于磁盘空间,因此才会有“绝对不能将所有的子图都放在内存中,等着最后一次性拼接”的事情。

该用户从未签到

发表于 2010-12-9 08:34:08 | 显示全部楼层
“对SlaveCamera做RenderTraverals时,控制台窗口就出现了该提示。显得十分无厘头。”,事实上SlaveCamera应该是绝少用到的,它的唯一作用是用于表达Powerwall的效果,其它任何的应用都应该直接在场景图中完成

“osgPosger是不能输出800000*600000的图片的”,看来您还没有仔细看过osgposter所有的参数

该用户从未签到

发表于 2010-12-9 09:54:23 | 显示全部楼层
13# array
osgPosger是不能输出800000*600000的图片的”,看来您还没有仔细看过osgposter所有的参数?
真的不行,开不了那么大的内存,存图片,我存bmp的好像是1G左右。

该用户从未签到

发表于 2010-12-9 13:22:36 | 显示全部楼层
有参数--disable-output-poster可以设置的……然后就不会分配最终输出图片的内存了~~唉,我们这里都用它来输出几十米见方的巨幅展板了……

该用户从未签到

发表于 2010-12-9 14:23:59 | 显示全部楼层
poster好东东啊~~

该用户从未签到

 楼主| 发表于 2010-12-10 16:50:46 | 显示全部楼层
由SlaveCamera改为PreRender的Camera,果然可以正常输出各种大图了。
不过这里有一点我很难理解的,虽然它现在并不影响我的工作了:
Array应该可以清楚地记得下面这点代码:
    osg::Matrix offsetMatrix =
        osg::Matrix::scale(_tileColumns, _tileRows, 1.0) *
        osg::Matrix::translate(_tileColumns-1-2*col, _tileRows-1-2*row, 0.0);

我先前在使用SlaveCamera时,也使用的这样的代码来计算相机偏移。当时我搞了一整个下午才搞出这个偏移矩阵。得到的效果是,不论采用何种方式来切割视口(m*n的任意切分视口),这个矩阵的偏移算法都是可以通用的。
但是我不知道Array有没有试验过,对于PreRender的Camera,竟然这个公式就没有了通用性了,只能将窗口切割成5*5、10*10、20*20、40*40、……方式。原则上,不论是采用PreRender的相机,还是Slave的相机,计算矩阵偏移都应该一样。可是事实上不一样了。千真万确。

Array可以如此试一试osgPoster程序:要求输出8000*6000的图片,然后每一个Tile指定为1000*750的,程序会死掉。若将Tile指定为800*600,或者400*300之类的,那么就没事了。我不知道原因何在。

另外还有,我的程序里面有大量的PageLOD节点(不仅具有VPB的地形,还有多级的建筑物)。osgPoster看样子是做了处理,试图载入最精细的那一级节点。遇到我这种情况,osgPoster也会等待很久,硬盘一直在闪,一直等待到我实在没有耐心之后杀掉进程。就此我是可以猜测到原因的,若我这场景全部采用精模,本来内存就不够。

而我的程序没有要求全部载入精模,可惜会在不经意之中随机地崩溃掉(有时候不崩),崩溃点位于很多级别的NodeVisitor遍历之中,崩溃堆栈那个深啊!我实在是没有耐心去找到崩溃的原因所在。

该用户从未签到

发表于 2010-12-10 17:00:29 | 显示全部楼层
Array可以如此试一试osgPoster程序:要求输出8000*6000的图片,然后每一个Tile指定为1000*750的,程序会死掉。若将Tile指定为800*600,或者400*300之类的,那么就没事了。我不知道原因何在。
答案是轻松渲染,osgposter已经用在实际生产中,我想它没有那么脆弱,只是您自己没有吃透而已

我的命令行为:
  1. osgposter --tilesize 1000 750 --finalsize 8000 6000 --use-fbo
复制代码
此外osgposter也不会载入全部精模,事实上它使用了比较复杂的过程来逐步载入最精细的级别,并且及时释放之前的——您的错误恐怕是您自己的问题

该用户从未签到

 楼主| 发表于 2010-12-10 19:38:51 | 显示全部楼层
我实在不好说啥了。也许在你那里运行很稳定,但是的确在我这里出问题了。包括前面我说到的问题,的确在我这里全部都有,而且100%重现。我真的是抱着学习的心态来提问,绝无诋毁你的程序的意思。但是这的确是事实。

该用户从未签到

 楼主| 发表于 2010-12-10 19:47:16 | 显示全部楼层
我在这里发帖,也绝对不是来抬杠的,那对学习毫无意义。
我前面提到的计算偏移矩阵,我们走到一块了,都是对投影矩阵进行偏移。那么,若指定只能对模型视图矩阵进行偏移,能够做到相同的效果么?

该用户从未签到

发表于 2010-12-13 08:43:18 | 显示全部楼层
我在这里发帖,也绝对不是来抬杠的
貌似我从未强调过您是在抬杠,也并不认为您要“诋毁”我的代码什么的,我只是对于您遇到的现象做出试验并尝试进行解释。到目前为止,我似乎没有发现这贴中有什么不和谐的气息?

此外您在第一帖中的问题似乎就比较明显了,您的FBO测试失败,这无疑会对基于RTT的截屏处理造成影响。因为FrameBuffer(内部其实是glReadPixels和glCopySubImage)的使用要考虑到当前窗口分辨率的大小。

那么,若指定只能对模型视图矩阵进行偏移,能够做到相同的效果么
我认为答案是没有希望,必须对投影矩阵做出处理

该用户从未签到

 楼主| 发表于 2010-12-14 18:12:29 | 显示全部楼层
感谢Array的技术支持,我这人是个急性子,遇到搞不定的问题时会无厘头的发飙。
关于我截图的问题,目前我已经解决,可以成功的输出数亿像素的大图。
这里需要总结一些:
1、不能使用Slave相机来实现这种分屏截图。理由未明。也许是OSG真的不希望我这么做。这里不明白的是,Slave相机能够成功的渲染到窗口中,为什么渲染到PIX_BUFFER上时,会漏掉PageLOD节点的纹理呢?这个问题暂时放一放,项目进度要求我只能浅尝则止,搞定了事。

2、关于我前面说到的,分块子图和合并之后的全图之间存在一定的比例关系问题,的确是存在的,最严重的情况是导致拼接起来的大图在右边或者上边出现部分空白。但这的确是一个牛角尖,我完全可以通过输入层来限制用户的输入,其实这种限制是相当小的,完全不会让用户觉得有多么的受限。如同osgPoster一样,其实很难感觉到存在这种限制。

3、关于前面说到的严重问题——PageLOD节点大量存在时,截图会随机地崩溃。该问题难以理解。最终我换用了osgPoster的思路,访问FrameStamp对帧计数,保证每一次输出的子图滞后至少一帧,这样它就一定被渲染过了。按照这个方式,完全不会发生崩溃,程序很稳定。
在以前,我是对截图的相机挂接了一个FinalDrawCallback,在该Callback中设置标识通知,通知一帧已经渲染完毕、可以输出子图。这里我也小心的使用了Mutex来保证标识量不冲突。可惜事实是我解决不了这种无厘头的崩溃问题(崩溃点处于渲染台中对PageLOD的遍历中,深深的堆栈!)。我前面断断续续的贴出了该FinalDrawCallback的全部代码,其实就那么一两行有用的代码,是不大可能出现问题的。

该用户从未签到

发表于 2010-12-15 10:37:44 | 显示全部楼层
osgposter已经正式加入到OSG核心,有修改意见的朋友欢迎直接对osg的代码进行调试和发表看法~~
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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