【问题标题】:OpenGL Texture rendering as blackOpenGL 纹理渲染为黑色
【发布时间】:2015-06-09 22:49:25
【问题描述】:

我正在使用 Siphon 框架尝试将视频帧从服务器推送到客户端应用程序。

Syphon 要求您使用 OpenGL 纹理而不是普通图像。

因此,我正在尝试将 CGImageRef 渲染为纹理并将其发送到发布。

我正在创建我的 CGL 上下文:

CGLPixelFormatAttribute attribs[13] = {
    kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core, // This sets the context to 3.2
    kCGLPFAColorSize,     (CGLPixelFormatAttribute)24,
    kCGLPFAAlphaSize,     (CGLPixelFormatAttribute)8,
    kCGLPFAAccelerated,
    kCGLPFADoubleBuffer,
    kCGLPFASampleBuffers, (CGLPixelFormatAttribute)1,
    kCGLPFASamples,       (CGLPixelFormatAttribute)4,
    (CGLPixelFormatAttribute)0
};

CGLPixelFormatObj pix;
GLint npix;
CGLChoosePixelFormat(attribs, &pix, &npix);

CGLCreateContext(pix, 0, &_ctx);

我已经有一个 CGImageRef,我知道它可以正确呈现为 NSImage。

我正在渲染纹理:

CGLLockContext(cgl_ctx);

if (_texture) {
    glDeleteTextures(1, &_texture);
}

int width = 1920;
int height = 1080;

GLubyte* imageData = malloc(width * height * 4);
CGContextRef imageContext = CGBitmapContextCreate(imageData, width, height, 8, width * 4, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, width, height), image);
CGContextRelease(imageContext);

GLuint frameBuffer;
GLenum status;

glGenFramebuffersEXT(1, &frameBuffer);

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer);
glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_2D, _texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_TEXTURE_2D, imageData);

status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
    NSLog(@"OpenGL Error");
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

CGLUnlockContext(cgl_ctx);

渲染代码在不同的类,但是上下文应该是通过的,是一样的。

我在几乎所有其他有关此问题的实例中都尝试了该建议,但均无济于事。

【问题讨论】:

    标签: objective-c opengl quartz-2d syphon


    【解决方案1】:

    glTexImage2D 中的倒数第二个参数是:

    类型
    指定像素数据的数据类型。接受以下符号值: GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, GL_FLOAT, GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, GL_UNSIGNED_SHORT_4_4_4_4, @987654334 @、GL_UNSIGNED_SHORT_5_5_5_1GL_UNSIGNED_SHORT_1_5_5_5_REVGL_UNSIGNED_INT_8_8_8_8GL_UNSIGNED_INT_8_8_8_8_REVGL_UNSIGNED_INT_10_10_10_2GL_UNSIGNED_INT_2_10_10_10_REV

    GL_TEXTURE_2D 在那里没有意义,它应该是imageData 元素的数据类型。

    您还应该使用glGetErrorARB_debug_output 检查您的OpenGL 错误。您会立即看到问题所在:

    Source:OpenGL   Type:Error  ID:5    Severity:High   Message:GL_INVALID_ENUM in glTexImage2D(incompatible format = GL_RGBA, type = GL_TEXTURE_2D)
    

    【讨论】:

    • 鉴于我的 imageContext,您对这种类型有何建议?我会使用 GL_UNSIGNED_BYTE 吗?
    • @JamEngulfer221 我不熟悉您使用的框架。但图像数据通常是浮点数或无符号整数。
    • 看代码,imageData的元素肯定是GLubyte,还是无符号字节?
    • @JamEngulfer221 如果它们是无符号字节,那么 GL_UNSIGNED_BYTE 就是你想要的类型,是的。
    • 另外,我怎样才能获得像您发布的错误报告?我似乎找不到关于使用你提到的东西的好文档。
    【解决方案2】:

    这段代码有一些问题。以下是让事情顺利进行的关键:

    • 正如@orost 在之前的回答中所指出的,glTexImage2D() 调用的 type 参数无效。应该是:

      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
                   GL_RGBA, GL_UNSIGNED_BYTE, NULL);
      
    • 纹理永远不会作为 FBO 目标附加。设置 FBO 时,您需要:

      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                             GL_TEXTURE_2D, _texture, 0);
      

    还有几个项目可能不会阻止您运行它,但我还是建议您更改它们:

    • 如果要通过渲染来创建内容,则无需为纹理指定数据。无论如何,您传递给glTexImage2D() 的数据都未初始化,因此没有多大用处。将NULL 作为 data 参数传递会更简洁,就像我在上面显示的调用中所做的那样。
    • 由于您使用的是 OpenGL 3.2,因此实际上没有必要使用 FBO 入口点的 EXT 形式。这是 OpenGL 3.x 中的标准功能。只要您始终如一地使用EXT 表单,它就可能会起作用,但是如果您将它与标准入口点混合使用,您可能会遇到丑陋的意外。

    【讨论】:

    • 查看我的代码,我认为 imageData 将被初始化,因为我认为我将图像绘制到以某种方式使用 imageData 的上下文中。
    • 关于指定数据的主题,该数据是我想要呈现的东西。如果我不包含它,则实际上没有要渲染的内容,因为在渲染代码中的其他任何地方都没有提到图像数据。
    • 我想我理解你的意图,但事实并非如此。当您将数据指针传递给glTexImage2D() 时,它仅在调用期间用于用数据填充纹理。指针不是与纹理永久关联的。如果您渲染到纹理,并且想要生成图像的 CPU 副本,则需要使用 glReadPixels() 将其读回。
    • 我刚刚阅读了glTexImage2D() 的文档,它似乎不同意你的观点。它说:If target is GL_TEXTURE_2D, ... data is read from data as a sequence of signed or unsigned bytes...
    • @JamEngulfer221 是的,这和我说的有什么不同? glTexImage2D() 调用会读取您在调用期间传入的数据。调用返回后,它不会以任何方式使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 2018-09-17
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    • 2018-02-17
    • 2016-07-23
    相关资源
    最近更新 更多