使用OSG获取模板缓冲区时的FBO错误

时间:2016-08-28 11:49:41

标签: opengl openscenegraph

我试图在OSG中使用离线渲染来获取节点的模板索引。我的主要程序如下:

  1. 深度复制我想离线渲染的节点并获取模板索引;
  2. 创建一个离线渲染摄影机,并将之前复制的节点作为摄像机的子节点,然后将此摄像机作为子节点添加到我想要离线渲染的原始节点;
  3. 创建一个DrawCallback,它获取模板缓冲区并检查每个像素的模板索引,并获得最大的模板索引。
  4. 好的,程序看起来有点长。现在我可以获得正确的最大模板索引,但是,我收到了警告和错误:

    " RenderStage :: runCameraSetUp(),FBO设置失败,FBO状态= 0x8cdd" "警告:检测到OpenGL错误'无效操作'在SceneView :: draw()的末尾 ..."

    整个代码有点冗长乏味。下面列出了一些主要代码段:

    void OfflineCallback::operator()(osg::RenderInfo &renderInfo)const
    {
        osg::Image *image = new osg::Image;
        image->readPixels(0, 0, 512, 512, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE);
        unsigned char *dtBuf = (unsigned char *)(image->getDataPointer());
        int maxStencil = 0;
        for (int i = 0; i != image->s(); ++i){
            for (int j = 0; j != image->t(); ++j){
                unsigned char dt = dtBuf[image->s() * i + j];
                if(dt > maxStencil)
                    maxStencil = dt;
            }
        }
    }
    

    然后我创建离线渲染摄像头,并附加模板缓冲区:

    osg::Camera *camera = new osg::Camera;
    camera->setClearMasks(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
    camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
    camera->attach(osg::Camera::STENCIL_BUFFER, GL_UNSIGNED_BYTE);
    
    osg::Stencil *stencil = new osg::Stencil;
    stencil->setFunction(osg::Stencil::GREATER, 1, 0xff);
    stencil->setOperation(osg::Stencil::INCR, osg::Stencil::INCR, osg::Stencil::INCR);
    osg::Depth *depth = new osg::Depth;
    depth->setFunction(osg::Depth::ALWAYS);
    
    osg::StateSet *ss = camera->getOrCreateStateSet();
    ss->setAttributeAndModes(stencil, osg::StateAttribute::ON);
    ss->setAttributeAndModes(depth, osg::StateAttribute::ON);
    camera->setPostDrawCallback(new OfflineCallback);
    

    为了测试代码,我创建了一个球体作为主节点,然后我得到最大的模板索引为2,这是正确的但是在开头提到了错误和警告。

    我错过了什么?哪一步错了?任何建议将不胜感激。谢谢!

    此致 麦

2 个答案:

答案 0 :(得分:1)

这个电话看起来很可疑:

camera->attach(osg::Camera::STENCIL_BUFFER, GL_UNSIGNED_BYTE);

我还没有使用OSG,但根据文档,此方法的第二个参数是 internalFormat ,它直接对应于内部格式的OpenGL GLenum值模板附件。 GL_UNSIGNED_BYTE不是模板缓冲区的有效值内部格式。这需要是GL_STENCIL_INDEX,或其大小的变体之一。例如:

camera->attach(osg::Camera::STENCIL_BUFFER, GL_STENCIL_INDEX8);

除此之外,0x8cddGL_FRAMEBUFFER_UNSUPPORTED的值。这意味着(稍微从规范中解释),"附加图像的内部格式的组合违反了依赖于实现的一组限制。"

OpenGL实现可以为未按要求指定的任何附件组合提供此错误,如第34节中所述; 9.4.3所需的帧缓冲区格式"在OpenGL 4.5规范中。

如果在修复模板格式后仍然出现此错误,我强烈怀疑您的尝试失败,因为您使用单独的缓冲区进行深度和模板。第9.4.3节中具体提到了这种情况:

  

但是,当存在深度和模板附件时,仅需要实现支持帧缓冲对象,其中两个附件都引用相同的图像。

当需要深度和模板时,供应商通常只支持组合深度/模板。在内部,通常有一个32位/像素缓冲区,24位深度和8位模板数据。

所以如果你现在有这样的东西:

camera->attach(osg::Camera::DEPTH_BUFFER, GL_DEPTH_COMPONENT24);
...
camera->attach(osg::Camera::STENCIL_BUFFER, GL_STENCIL_INDEX8);

如果希望代码在大多数平台上运行,则应使用组合深度/模板缓冲区:

camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH24_STENCIL8);

答案 1 :(得分:1)

好的,最后我得到了正确的模板索引,更重要的是没有任何错误和警告!

Reto的答案仍然非常有用。再次感谢你,Reto!他的主要观点是,如果你想要获得深度和同时模板缓冲区,大多数供应商只会为您提供打包深度模板缓冲区。

换句话说,如果你附上深度&模板缓冲区同时独立于FBO,你很可能无法创建FBO。这就是我在第一时间得到错误和警告的实际原因。

详细原因是:OSG相机隐含地创建了颜色&深度缓冲区,而不创建模板缓冲区。对大多数情况来说这没什么问题。但是,就我而言,我明确地想要模板缓冲区。最后,OSG相机为我创建了所有三个缓冲区。如前所述,独立深度&模板缓冲区会导致FBO创建失败,因此我收到所有警告和错误。

解决方案:

image->allocateImage(512, 512, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE);
camera->attach(osg::Camera::STENCIL_BUFFER, image);
//explicitly tells camera not to implicitly create color & depth buffers
camera->setImplicitBufferAttachmentRenderMask(0);

在DrawCallback中,您可以轻松读取模板索引,就像读取深度缓冲区一样。

如果有人有其他想法或更正,我全都听见了!