OpenGL 纹理渲染为黑色
OpenGL Texture rendering as black
我正在使用 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);
渲染代码不一样class,但是context应该是通过的,是一样的
我在几乎所有其他情况下都尝试过此问题的建议,但无济于事。
glTexImage2D
中的倒数第二个参数是:
type
Specifies the data type of the pixel data. The following symbolic values are accepted:
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
, GL_UNSIGNED_SHORT_4_4_4_4_REV
, GL_UNSIGNED_SHORT_5_5_5_1
, GL_UNSIGNED_SHORT_1_5_5_5_REV
, GL_UNSIGNED_INT_8_8_8_8
, GL_UNSIGNED_INT_8_8_8_8_REV
, GL_UNSIGNED_INT_10_10_10_2
, and GL_UNSIGNED_INT_2_10_10_10_REV
.
GL_TEXTURE_2D
在那里没有意义,它应该是 imageData
元素的任何数据类型。
您还应该使用 glGetError
或 ARB_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)
此代码中存在一些问题。以下是使事情正常进行的关键:
正如@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,因此实际上没有必要使用
EXT
形式的 FBO 入口点。这是 OpenGL 3.x 中的标准功能。 EXT
表单可能会在您始终如一地使用它时发挥作用,但如果将它与标准入口点混合使用,您可能会遇到丑陋的惊喜。
我正在使用 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);
渲染代码不一样class,但是context应该是通过的,是一样的
我在几乎所有其他情况下都尝试过此问题的建议,但无济于事。
glTexImage2D
中的倒数第二个参数是:
type
Specifies the data type of the pixel data. The following symbolic values are accepted: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
,GL_UNSIGNED_SHORT_4_4_4_4_REV
,GL_UNSIGNED_SHORT_5_5_5_1
,GL_UNSIGNED_SHORT_1_5_5_5_REV
,GL_UNSIGNED_INT_8_8_8_8
,GL_UNSIGNED_INT_8_8_8_8_REV
,GL_UNSIGNED_INT_10_10_10_2
, andGL_UNSIGNED_INT_2_10_10_10_REV
.
GL_TEXTURE_2D
在那里没有意义,它应该是 imageData
元素的任何数据类型。
您还应该使用 glGetError
或 ARB_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)
此代码中存在一些问题。以下是使事情正常进行的关键:
正如@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,因此实际上没有必要使用
EXT
形式的 FBO 入口点。这是 OpenGL 3.x 中的标准功能。EXT
表单可能会在您始终如一地使用它时发挥作用,但如果将它与标准入口点混合使用,您可能会遇到丑陋的惊喜。