简体   繁体   English

使用GLKit openGL - iOS绘制YUV图像

[英]Draw YUV image using GLKit openGL - iOS

I want to render a yuv image on an iOS device. 我想在iOS设备上渲染yuv图像。 I presume it can be achieved using openGL. 我认为可以使用openGL来实现。 (Actually I have to render multiple such images in succession) (实际上我必须连续渲染多个这样的图像)

What I understand is that GLKit is an abstraction that iOS created, in which there is a GLKView which will have and handle the render buffer. 我理解的是,GLKit是iOS创建的一个抽象,其中有一个GLKView将拥有并处理渲染缓冲区。 I am currently trying to use a GLKViewController and frame update is being done successfully with desired fps. 我目前正在尝试使用GLKViewController并且正在使用所需的fps成功完成帧更新。 This I conform by using glClear function call. 这个我通过使用glClear函数调用。

Now the task is to render an image on the view. 现在的任务是在视图上渲染图像。

There is a class GLKBaseEffect which will have basic shaders. 有一个类GLKBaseEffect ,它将具有基本着色器。 I can't figure out what properties to set, so I just create it and call prepareToDraw before each render. 我无法弄清楚要设置的属性,所以我只是创建它并在每次渲染之前调用prepareToDraw

There is a class for handling textures, GLKTextureLoader , but it appears to me that it only works with Quartz images, ie, yuv420 planar can't be loaded into the texture using this class. 有一个用于处理纹理的类, GLKTextureLoader ,但在我看来它只适用于Quartz图像,即yuv420 plane无法使用此类加载到纹理中。

// 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);  

I use this code for generating a texture and binding it, but I don't really know what I am trying to do here. 我使用此代码生成纹理并绑定它,但我真的不知道我在这里尝试做什么。 And whatever it is, it doesn't bring up any image on screen, and I don't know what to do next. 无论它是什么,它都不会在屏幕上显示任何图像,我不知道接下来该做什么。

I have not created any shaders, assuming baseEffect will have something. 我没有创建任何着色器,假设baseEffect将有一些东西。

And this https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html#//apple_ref/doc/uid/TP40008793-CH103-SW8 tells me that I'll have to use EAGLayer to render images on screen. 这个https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html#//apple_ref/doc/uid/TP40008793-CH103-SW8告诉我,我会有使用EAGLayer在屏幕上渲染图像。

Can I use GLKit to render images? 我可以使用GLKit渲染图像吗? If YES, do we have any sample code or tutorial that wouldn't use GLKTextureLoader class (I couldn't find any)? 如果是,我们是否有任何不使用GLKTextureLoader类的示例代码或教程(我找不到)? If NO, is there a similar tutorial for render using EAGLLayer (I have not explored about it till now) ? 如果没有,是否有类似的使用EAGLLayer进行渲染的教程( EAGLLayer我还没有探讨过)?

It sounds like you're really asking about a few different topics here: 听起来你真的在这里询问一些不同的主题:

  • How to draw with GLKView vs CAEAGLLayer 如何使用GLKViewCAEAGLLayer绘制
  • How GLKBaseEffect and GLKTextureLoader fit into OpenGL ES drawing in general GLKBaseEffectGLKTextureLoader如何适用于OpenGL ES绘图
  • How to draw a texture once you have one 一旦有了纹理,如何绘制纹理
  • How to render YUV image data 如何渲染YUV图像数据

I'll try to address each in turn... 我会尝试依次解决每个问题......


GLKView is just fine for any OpenGL ES drawing you want to do -- it does everything that the older documentation you linked to does (setting up framebuffers, CAEAGLLayer s, etc) for you so you don't have to write that code. GLKView适用于您想要做的任何OpenGL ES绘图 - 它可以完成您链接的旧文档所做的一切(为您设置framebuffers, CAEAGLLayer等),因此您不必编写该代码。 Inside the GLKView drawing method ( drawRect: or glkView:drawInRect: , depending on whether you're drawing in a subclass or delegate), you write the same OpenGL ES drawing code you would for CAEAGLLayer (or any other system). GLKView绘图方法( drawRect:glkView:drawInRect:取决于您是否在子类或委托中绘图)中,您编写了与CAEAGLLayer (或任何其他系统)相同的OpenGL ES绘图代码。


You can use GLKView , GLKTextureLoader , and GLKBaseEffect independently of each other. 您可以相互独立地使用GLKViewGLKTextureLoaderGLKBaseEffect If you want to write all your own drawing code and use your own shaders, you can draw in a GLKView without using GLKBaseEffect . 如果要编写所有自己的绘图代码并使用自己的着色器,可以在不使用GLKBaseEffect情况下绘制GLKView (You can even mix and match GLKBaseEffect and your own stuff, like you see when you create a new Xcode project with the OpenGL Game template.) Likewise, GLKTextureLoader loads image data and spits out the name you'll need for binding it for drawing, and you can use that regardless of whether you're drawing it with GLKBaseEffect . (您甚至可以混合和匹配GLKBaseEffect和您自己的东西,就像您在使用OpenGL游戏模板创建新的Xcode项目时所看到的那样。)同样, GLKTextureLoader加载图像数据并吐出您需要的name来绑定它以进行绘制,无论您是否使用GLKBaseEffect绘制它,都可以使用它。


Once you get a texture, whether via GLKTextureLoader or reading/decoding the data yourself and providing it to glTexImage2D , there are three basic steps to drawing with it: 一旦获得纹理,无论是通过GLKTextureLoader还是自己读取/解码数据并将其提供给glTexImage2D ,使用它绘制有三个基本步骤:

  1. Bind the texture name with glBindTexture . 使用glBindTexture绑定纹理名称。
  2. Draw some geometry to be textured (using glDrawArrays , glDrawElements , or similar) 绘制一些要纹理化的几何体(使用glDrawArraysglDrawElements或类似物)
  3. Have a fragment shader that looks up texels and outputs colors. 有一个片段着色器,可以查找纹素并输出颜色。

If you just want to draw an image that fills your view, just draw a quad (two triangles). 如果您只想绘制填充视图的图像,只需绘制四边形(两个三角形)。 Here's the code I use to set up a vertex array object with one quad when I want to draw fullscreen: 这是我想用于绘制全屏时使用一个四边形设置顶点数组对象的代码:

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);

Then, to draw it: 然后,绘制它:

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

That's just the geometry-drawing part. 这只是几何绘图部分。 Combine this with a GLKBaseEffect -- whose transform property is the default identity transform, and whose texture2d0 property is set up with the name of a texture you've loaded via GLKTextureLoader or other means -- and you'll get a view-filling billboard with your texture on it. 将它与GLKBaseEffect结合 - 其transform属性是默认的标识转换,其texture2d0属性设置为您通过GLKTextureLoader或其他方式加载的纹理的name - 您将获得一个视图填充广告牌你的纹理就可以了。


Finally, the YUV part... for which I'll mostly punt. 最后,YUV部分......我将大部分时间。 Where are you getting your YUV texture data? 你在哪里获得YUV纹理数据? If it's from the device camera, you should look into CVOpenGLESTexture / CVOpenGLESTextureCache , as covered by this answer . 如果它来自设备相机,您应该查看CVOpenGLESTexture / CVOpenGLESTextureCache ,如本答案所述 Regardless, you should be able to handle YUV textures using the APPLE_rgb_422 extension, as covered by this answer . 无论如何,您应该能够使用APPLE_rgb_422扩展来处理YUV纹理,如本答案所述 You can also look into this answer for some help writing fragment shaders to process YUV to RGB on the fly. 您还可以查看此答案,以获得一些帮助编写片段着色器以便在运行时将YUV处理为RGB。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM