OpenGL纹理渲染为黑色

时间:2015-06-09 22:49:25

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

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

Siphon要求您使用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);

渲染代码位于不同的类中,但上下文应该通过并且是相同的。

我几乎在这个问题的每个其他实例中都尝试过这个建议无济于事。

2 个答案:

答案 0 :(得分:1)

glTexImage2D中倒数第二个参数是:

  

键入
  指定像素数据的数据类型。接受以下符号值:   GL_UNSIGNED_BYTEGL_BYTEGL_UNSIGNED_SHORTGL_SHORTGL_UNSIGNED_INTGL_INTGL_FLOATGL_UNSIGNED_BYTE_3_3_2,{{ 1}},GL_UNSIGNED_BYTE_2_3_3_REVGL_UNSIGNED_SHORT_5_6_5GL_UNSIGNED_SHORT_5_6_5_REVGL_UNSIGNED_SHORT_4_4_4_4GL_UNSIGNED_SHORT_4_4_4_4_REVGL_UNSIGNED_SHORT_5_5_5_1GL_UNSIGNED_SHORT_1_5_5_5_REV,{{1} },GL_UNSIGNED_INT_8_8_8_8GL_UNSIGNED_INT_8_8_8_8_REV

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

您还应该使用GL_TEXTURE_2DimageData检查您的OpenGL错误。你会立刻被证明是错的:

glGetError

答案 1 :(得分:1)

此代码中存在一些问题。以下是让工作顺利进行的关键:

  • 正如@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作为数据参数传递得更清晰,正如我在上面显示的调用中所做的那样。
  • 由于您使用的是OpenGL 3.2,因此无需使用FBO入口点的EXT形式。这是OpenGL 3.x中的标准功能。 EXT表单可能会一直使用,但如果将它与标准入口点混合,则可能会出现难看的惊喜。