如何从ARGB NSImage加载OpenGL纹理而无需滑动?

如何从ARGB NSImage加载OpenGL纹理而无需滑动?,opengl,jpeg,loading,nsimage,argb,Opengl,Jpeg,Loading,Nsimage,Argb,我正在为Mac OS>=10.6编写一个应用程序,它可以从磁盘加载的图像中创建OpenGL纹理 首先,我将图像加载到NSImage中。然后,我从图像中获取NSBitmapImageRep,并使用glTexImage2D将像素数据加载到纹理中 对于RGB或RGBA图像,它可以完美地工作。我可以传入3字节/像素的RGB或4字节的RGBA,并创建一个4字节/像素的RGBA纹理 然而,我刚刚让一位测试人员给我发送了一张JPEG图像(在佳能EOS 50D上拍摄,不确定它是如何导入的),它似乎有ARGB字节

我正在为Mac OS>=10.6编写一个应用程序,它可以从磁盘加载的图像中创建OpenGL纹理

首先,我将图像加载到NSImage中。然后,我从图像中获取NSBitmapImageRep,并使用glTexImage2D将像素数据加载到纹理中

对于RGB或RGBA图像,它可以完美地工作。我可以传入3字节/像素的RGB或4字节的RGBA,并创建一个4字节/像素的RGBA纹理

然而,我刚刚让一位测试人员给我发送了一张JPEG图像(在佳能EOS 50D上拍摄,不确定它是如何导入的),它似乎有ARGB字节顺序

我在这个帖子上找到了一个帖子:(http://www.cocoabuilder.com/archive/cocoa/12782-coregraphics-over-opengl.html)这建议我指定一个格式参数GL_BGRA来 glTexImage2D和一种类型的GL_UNSIGNED_INT_8_8_8_8_REV

这似乎是合乎逻辑的,似乎应该奏效,但事实并非如此。我得到了不同但仍然错误的颜色值

我编写了“swizzling”(手动字节交换)代码,将ARGB图像数据洗牌到一个新的RGBA缓冲区中,但是对于大型图像来说,这种逐字节的swizzling会很慢

我也想了解如何使这项工作“正确的方式”

将ARGB数据加载到RGBA OpenGL纹理中的技巧是什么

我当前打给xxx的电话如下所示:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newWidth, newHeight, 0, format, GL_UNSIGNED_BYTE, pixelBuffer);
uniform sampler2D image;
void main()
{
    gl_FragColor = texture2D(image, gl_FragCoord.xy).gbar;
}
其中是RGB或RGBA

我尝试使用:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newWidth, newHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);
当我的图像代表报告它处于“alpha优先”顺序时


作为第二个问题,我还了解到大多数图形卡的“本机”格式是GL_BGRA,因此以该格式创建纹理可以加快纹理绘制速度。纹理绘制的速度比加载纹理的速度更重要,因此,将数据“快速”转换为BGRA格式是值得的。我试图让OpenGL通过指定GL_RGBA的“internalformat”来创建BGRA纹理,但结果是一幅完全黑色的图像。我对文档的解释使我期望,如果源格式和内部格式不同,glTexImage2D在读取数据时会对数据进行字节交换,但当我尝试指定GL_RGBA的“internalformat”时,会出现OpenGL错误0x500(GL_INVALID_ENUM)。我遗漏了什么?

我不知道如何将ARGB数据直接加载到纹理中,但有一个比在CPU上执行swizzle更好的解决方法。您可以在GPU上非常有效地执行此操作:

  • 将ARGB数据加载到临时RGBA纹理中
  • 使用此纹理绘制全屏四边形,同时使用简单的像素着色器渲染到目标纹理
  • 继续加载其他资源,无需暂停GPU管道
  • 像素着色器示例:

    #version 130
    uniform sampler2DRect unit_in;
    void main() {
        gl_FragColor = texture( unit_in, gl_FragCoord.xy ).gbar;
    }
    

    你是用OpenGL绘制的,对吗? 如果你想用简单的方法来做,你可以让你的像素着色器实时地旋转颜色。对于图形卡来说,这一点都没有问题,它们是用来做faar更复杂的事情的:)

    可以使用如下着色器:

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newWidth, newHeight, 0, format, GL_UNSIGNED_BYTE, pixelBuffer);
    
    uniform sampler2D image;
    void main()
    {
        gl_FragColor = texture2D(image, gl_FragCoord.xy).gbar;
    }
    

    如果您不了解着色器,请在此处阅读此图坦卡蒙:

    此问题很老,但如果其他人正在寻找此问题,我会找到一个严格安全但有效的解决方案。问题是每个32位RGBA值的第一个字节都有一个,而不是最后一个

    NBitmapImageRep.bitmapData为您提供指向第一个字节的指针,该字节作为指向其像素的指针提供给OpenGL。只需将1添加到该指针,您就可以按正确的顺序指向RGB值,并在末尾显示下一个像素的A


    这样做的问题是,最后一个像素将从图像末尾以外的一个字节中获取A值,而A值都是一个像素。但是像询问者一样,我在加载JPG时得到这个,所以alpha无论如何都是不相关的。这似乎不会引起问题,但我不会声称它是“安全的”。

    数据为ARGB格式的纹理的名称

    GLuint argb_texture;
    
    用于在一次函数调用中设置ARGB swizzle的令牌数组

    static const GLenum argb_swizzle[] =
    {
       GL_GREEN, GL_BLUE, GL_ALPHA, GL_RED
    };
    
    绑定ARGB纹理

    glBindTexture(GL_TEXTURE_2D, argb_texture);
    
    在对glTexParameteriv的一次调用中设置所有四个swizzle参数

    glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, argb_swizzle);
    
    我知道这项工作,但我不确定Argbu swizzle的顺序是否正确。如果这不对,请纠正我。我不太清楚在argb_swizzle中GL_绿、GL_蓝、GL_α、GL_红是如何确定的

    根据建议:

    …这是一种允许您重新排列组件的机制 图形读取纹理数据时纹理数据的动态顺序 硬件


    我不明白你的答案是如何延伸到我的,那么重点是什么呢?此外,您的代码不正确:gl_FragCoord是一个窗口坐标,未规范化,因此您无法使用它采样“sampler2D”:PMy应用程序是使用固定管道OpenGL编写的(没有片段着色器)。我现在已经在iOS上完成了基于着色器的编程,但还没有在Mac OS上解决这个问题。如何将固定管道OpenGL与只进行旋转的片段着色器混合使用?我已经很久没有使用固定函数GL了,但据我回忆,绑定像素着色器只会覆盖一些固定函数状态,因此您应该确保该着色器也执行固定函数部分所使用的所有操作,我是一个noob@kvark,我可以分享一个例子吗