【问题标题】:Draw YUV image using GLKit openGL - iOS使用 GLKit openGL 绘制 YUV 图像 - iOS
【发布时间】:2013-09-18 14:34:31
【问题描述】:

我想在 iOS 设备上渲染 yuv 图像。我认为它可以使用openGL来实现。 (其实我得连续渲染多张这样的图)

我的理解是 GLKit 是 iOS 创建的一个抽象,其中有一个 GLKView 将拥有并处理渲染缓冲区。我目前正在尝试使用GLKViewController,并且正在使用所需的 fps 成功完成帧更新。我通过使用glClear 函数调用来遵守这一点。

现在的任务是在视图上渲染图像。

有一个类GLKBaseEffect 将有基本的着色器。我不知道要设置什么属性,所以我只是创建它并在每次渲染之前调用prepareToDraw

有一个用于处理纹理的类GLKTextureLoader,但在我看来它只适用于 Quartz 图像,即无法使用此类将 yuv420 平面加载到纹理中。

// create the texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, [imageNSData bytes]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);  

我使用此代码生成纹理并绑定它,但我真的不知道我要在这里做什么。不管它是什么,它都不会在屏幕上显示任何图像,我不知道下一步该做什么。

我没有创建任何着色器,假设 baseEffect 会有一些东西。

这个https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html#//apple_ref/doc/uid/TP40008793-CH103-SW8 告诉我,我必须使用 EAGLayer 在屏幕上渲染图像。

我可以使用 GLKit 来渲染图像吗?如果是,我们是否有任何不使用GLKTextureLoader 类的示例代码或教程(我找不到)?如果否,是否有类似的使用EAGLLayer 进行渲染的教程(我到目前为止还没有探索过)?

【问题讨论】:

    标签: ios opengl-es rendering glkit


    【解决方案1】:

    听起来你真的在这里问几个不同的话题:

    • 如何使用GLKViewCAEAGLLayer 进行绘图
    • GLKBaseEffectGLKTextureLoader 在一般情况下如何适应 OpenGL ES 绘图
    • 拥有纹理后如何绘制纹理
    • 如何渲染 YUV 图像数据

    我会尝试依次解决每个问题...


    GLKView 非常适合您想要执行的任何 OpenGL ES 绘图——它可以为您完成您链接到的旧文档所做的所有事情(设置帧缓冲区、CAEAGLLayers 等),因此您不需要必须编写该代码。在 GLKView 绘图方法(drawRect:glkView:drawInRect:,取决于您是在子类还是委托中绘图)中,您编写与 CAEAGLLayer(或任何其他系统)相同的 OpenGL ES 绘图代码.


    您可以相互独立地使用GLKViewGLKTextureLoaderGLKBaseEffect。如果您想编写所有自己的绘图代码并使用自己的着色器,您可以在不使用GLKBaseEffect 的情况下绘制GLKView。 (你甚至可以混合和匹配GLKBaseEffect 和你自己的东西,就像你在使用 OpenGL 游戏模板创建一个新的 Xcode 项目时看到的那样。)同样,GLKTextureLoader 加载图像数据并吐出name 你会绘制需要绑定,不管用GLKBaseEffect绘制都可以使用。


    一旦获得纹理,无论是通过GLKTextureLoader 还是自己读取/解码数据并将其提供给glTexImage2D,使用它进行绘制都需要三个基本步骤:

    1. 将纹理名称与glBindTexture绑定。
    2. 绘制一些要纹理化的几何体(使用glDrawArraysglDrawElements 或类似方法)
    3. 拥有一个片段着色器,用于查找纹素并输出颜色。

    如果您只想绘制填充视图的图像,只需绘制一个四边形(两个三角形)。当我想全屏绘制时,这是我用来设置一个带有一个四边形的顶点数组对象的代码:

    typedef struct __attribute__((packed)) {
        GLKVector3 position;
        GLKVector2 texcoord;
    } Vertex;
    
    static Vertex vertexData[] = {
        {{-1.0f,  1.0f, -1.0f}, {0.0f,  0.0f}},
        {{-1.0f, -1.0f, -1.0f}, {0.0f,  1.0f}},
        {{ 1.0f,  1.0f, -1.0f}, {1.0f,  0.0f}},
        {{ 1.0f, -1.0f, -1.0f}, {1.0f,  1.0f}},
    };
    
    glGenVertexArraysOES(1, &_vertexArray);
    glBindVertexArrayOES(_vertexArray);
    
    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
    
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid *)offsetof(Vertex, position));
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid *)offsetof(Vertex, texcoord));
    glBindVertexArrayOES(0);
    

    然后,绘制它:

    glBindVertexArrayOES(_vertexArray);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    

    这只是几何绘图部分。将其与GLKBaseEffect 结合使用——其transform 属性是默认的恒等变换,其texture2d0 属性是使用您通过GLKTextureLoader 或其他方式加载的纹理的name 设置的——你会得到一个充满视野的广告牌,上面有你的纹理。


    最后,YUV 部分……我将主要针对它。你从哪里得到你的 YUV 纹理数据?如果它来自设备摄像头,您应该查看CVOpenGLESTexture/CVOpenGLESTextureCache,如this answer 所涵盖。无论如何,您应该能够使用 APPLE_rgb_422 扩展来处理 YUV 纹理,正如 this answer 所涵盖的那样。您还可以查看 this answer 以获取一些帮助,帮助您编写片段着色器以动态处理 YUV 到 RGB。

    【讨论】:

    • 感谢您的回答,这是一个很大的帮助。关于 yuv 部分,我们真的必须在发送渲染之前将其转换为 rgb 数据吗?是不是有一种方法可以让我们将 yuv 缓冲区传递给 openGL 框架,然后它自己处理转换?我得到的是,我必须先使用顶点着色器创建一个矩形,然后在该区域渲染图像,对吗?
    • 所有像素数据最终都需要是RGB——屏幕是RGB设备!据我所知,没有办法在 OpenGL 纹理中为您完成 YUV 到 RGB 的转换,但您的片段着色器可以在最后一刻进行转换,如 GLCameraRipple 示例代码中所示。
    • 是的。这是我刚下载的。我想我现在会弄清楚方法,感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    • 2023-03-13
    • 2013-10-04
    相关资源
    最近更新 更多