(OpenGL)如何读取纹理缓冲区?

9

glGetBufferSubData是否同时用于普通缓冲和纹理缓冲? 我正在尝试解决我的纹理不显示的问题,当我使用glGetBufferSubData读取缓冲区时,我得到了一些垃圾数据。

struct TypeGLtexture //Associate texture data with a GL buffer
{
    TypeGLbufferID GLbuffer;
    TypeImageFile  ImageFile;

    void GenerateGLbuffer   ()
    {
        if (GLbuffer.isActive==true || ImageFile.GetPixelArray().size()==0) return;
        GLbuffer.isActive=true;
        GLbuffer.isTexture=true;
        GLbuffer.Name="Texture Buffer";
        GLbuffer.ElementCount=ImageFile.GetPixelArray().size();

        glEnable(GL_TEXTURE_2D);
        glGenTextures (1,&GLbuffer.ID);              //instantiate ONE buffer object and return its handle/ID
        glBindTexture (GL_TEXTURE_2D,GLbuffer.ID);   //connect the object to the GL_TEXTURE_2D docking point
        glTexImage2D (GL_TEXTURE_2D,0,GL_RGB,ImageFile.GetProperties().width, ImageFile.GetProperties().height,0,GL_RGB,GL_UNSIGNED_BYTE,&(ImageFile.GetPixelArray()[0]));

if(ImageFile.GetProperties().width==6){
    cout<<"Actual Data"<<endl;
    for (unsigned i=0;i<GLbuffer.ElementCount;i++) cout<<(int)ImageFile.GetPixelArray()[i]<<" ";
    cout<<endl<<endl;

    cout<<"Buffer data"<<endl;
    GLubyte read[GLbuffer.ElementCount]; //Read back from the buffer (to make sure)
    glGetBufferSubData(GL_TEXTURE_2D,0,GLbuffer.ElementCount,read);
    for (unsigned i=0;i<GLbuffer.ElementCount;i++) cout<<(int)read[i]<<" ";
    cout<<endl<<endl;} 
}

在此输入图像描述



编辑: 使用 glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_UNSIGNED_BYTE,read);
数据仍有差异: 在此输入图像描述


2
根据文档, GL_TEXTURE_2D不是glGetBufferSubData允许的参数之一。你是指GL_TEXTURE_BUFFER吗?实际上,我在代码中没有看到任何提示表明你真正处理纹理缓冲区。如果你是指普通纹理,那么glGetTexImage会帮助你。 - BDL
1个回答

10

如果这确实是纹理缓冲区之一,那么这样做是可行的。

glGetBufferSubData(...) 是用于 缓冲对象 的函数。而在这里,您有一个 纹理对象,如果您调用 glGetError(...) 检查错误状态,实际上应该会出现 API 错误。这是因为 GL_TEXTURE_2D 不是缓冲目标,而是一种纹理对象类型。

不幸的是,您混淆了术语。更不幸的是,还有一种名为缓冲纹理(它是一种特殊的 1D 纹理),允许您将缓冲对象视为非常有限的纹理形式。

与其宽泛地使用“缓冲器”来思考这些事情,您应该考虑“数据存储”。这是 OpenGL 使用的术语,以避免任何歧义;纹理对象具有数据存储器,缓冲对象也有。除非您创建一个纹理缓冲对象来链接这两个东西,否则它们是不同的概念。

从纹理对象读取数据比这更加复杂。

在 OpenGL 中,要从任何东西中读取像素数据之前,您必须定义像素格式和数据类型。OpenGL 被设计为将数据从纹理的内部格式转换为您请求的任何(兼容)格式。这就是您实际上正在寻找的函数具有以下签名的原因:

void glGetTexImage (GLenum      target,
                    GLint       level,
                    GLenum      format, // GL will convert to this format
                    GLenum      type,   // Using this data type per-pixel
                    GLvoid *    img);

这适用于所有存储像素数据的OpenGL对象。实际上,您可以使用Pixel Buffer Object(像素缓冲对象)将纹理对象中的像素数据传输到一个单独的缓冲对象中。glGetBufferSubData (...)可在该像素缓冲对象上使用,就像您最初尝试做的那样。


谢谢您澄清这个问题(我是OpenGL的新手,大部分内容都超出了我的理解范围)。 - Thomas An
切换到--> glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_UNSIGNED_BYTE,read); -->但数据仍然不相同...我现在讨厌OpenGL。 - Thomas An
1
@ThomasAn:你的原始图像数据尺寸是多少?与RGB图像格式和对齐有关的一个警告我没有提到。当将数据传输到/从OpenGL时,像素数据行应该从4字节边界开始。如果您的图像尺寸不是2的幂,则会遇到对齐问题。glPixelStorei(GL_UNPACK_ALIGNMENT, 1)可以解决这个问题(解包是上传数据时发生的事情,打包是下载数据时发生的事情)。 - Andon M. Coleman
我的图像是6x6的...我以为处理BMP行填充就足够了(而且2的幂只在GL 3.0之前有用)...但是问题似乎永远不会停止。再次感谢这个提示。 - Thomas An
1
@ThomasAn:啊,实际上如果你保留BMP数据不做任何修改,并且不触碰像素存储参数,你就会自动以GL想要的方式提供数据。2的幂次方并不是你想象中的那样,它只是一个愉快的巧合,即3乘以任何大于2的2的幂次方都能被4整除(这是你需要关注的规则)。有一组更大的尺寸可以满足行对齐,但是2的幂次方行宽始终如此,并且这种方式更容易解释 ;) - Andon M. Coleman
你给我的每一个提示都非常准确。现在我已经成功运行了,多亏了您先生。非常感谢! - Thomas An

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接