0

我正在使用 GLKit,在 24 fps 时,我需要使用 CGImageRef(无 alpha 层)并将另一个 CGImageRef(无 alpha 层)作为蒙版(黑白图像)并将结果渲染为 GLKit 纹理。

起初我尝试了这种方法:

CGImageRef actualMask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                          CGImageGetHeight(maskRef),
                                          CGImageGetBitsPerComponent(maskRef),
                                          CGImageGetBitsPerPixel(maskRef),
                                          CGImageGetBytesPerRow(maskRef),
                                          CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask(imgRef, actualMask);

虽然在将生成的 UIImage 分配给 UIImageView 时会起作用,但这不会作为 GLKit 纹理工作(不会应用蒙版)。但是,如果我使用以下方法重绘图像:

UIImage *maskedImg = [UIImage imageWithCGImage:masked];
UIGraphicsBeginImageContext(maskedImg.size);
[maskedImg drawInRect:CGRectMake(0, 0, maskedImg.size.width, maskedImg.size.height)];
UIImage* resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

生成的图像将被屏蔽并在 GLKit 纹理中正确渲染。但是,这会将 iPhone 4S 的性能降低到大约 6 fps。

我尝试过这种掩蔽方法但没有成功。

我已经尝试在没有 Core Graphics 的情况下使用 GLKit 混合来执行此操作,如 Ray Wenderlich 在此示例中所示。但是,这需要蒙版上的 alpha 透明度,这对我来说是一个交易破坏者。

我还发现了一个有趣的例子,它用一个名为 AVAnimator 的库和一个名为 KittyBoom 的例子来做我想做的。他们在这里手动替换像素。我想使用 GLKit 得到同样的结果。

任何进一步的方向或指导都会在这里有所帮助。提前致谢。

4

1 回答 1

2

GLKit 是一个具有四个主要组件的框架,可以一起使用或单独使用:视图/视图控制器、数学库、纹理加载器和效果。我从你的问题推测你所关心的问题GLKBaseEffect

有人可能会说GLKBaseEffect,生活的目的是让日常事务变得简单。它主要是替代 OpenGL ES 1.1 固定功能管道和使用它完成的一些常见技巧。

您所追求的不是常规的固定功能管道任务,因此要做好它意味着超越基本功能GLKBaseEffect并编写自己的着色器。这就是坏消息。好消息是,一旦您进入着色器世界,这非常容易。另一个好消息是您可以期待出色的性能——您可以在 GPU 上完成,而不是使用 CPU 进行 CoreGraphics 混合。

如果您不熟悉 OpenGL ES 2.0(或 3.0)着色器,“困难”部分是用GLKBaseEffect具有相同功能的自定义代码替换客户端 OpenGL ES 代码和顶点着色器。不过,这里有很多示例代码和教程。(由于您一直在关注 Ray Wenderlich 的网站,我相信您会在那里找到一些不错 。)您需要在这里做的主要事情是:

  1. 将用于命令的坐标空间中的顶点转换glDraw为剪辑空间。对于 2D 的东西,这很容易,因为您可以使用与GLKBaseEffect'transform属性相同的矩阵设置。
  2. 加载你的两个纹理(GLKTextureLoader在这里可以帮助你很多)并将它们绑定到两个纹理单元。
  3. 在您的客户端代码中,将每个顶点与一些纹理坐标相关联。(你可能已经这样做了。)
  4. 在您的顶点着色器中,从uniform输入中获取纹理坐标并将它们传递给varying输出。(除非您出于某种原因想要转换坐标,否则您无需执行任何其他操作。)

在所有这些设置之后,实际完成您所追求的效果的部分非常简单,并且都在您的片段着色器中:

// texture units bound in client code
uniform sampler2D colorTexture;
uniform sampler2D maskTexture;

// texture coordinate passed in from vertex shader
// (and automatically interpolated across the face of the polygon)
varying mediump vec2 texCoord;

void main() {
    // read a color from the color texture
    lowp vec3 color = texture2D(colorTexture, texCoord).rgb;

    // read a gray level from the mask texture
    // (the mask is grayscale, so we only need one component
    //  of its color because the others are the same)
    lowp float maskLevel = texture2D(maskTexture, texCoord).r;

    // use the gray level from the mask as the alpha value in the output color
    gl_FragColor = vec4(color, maskLevel);
}

此外,由于您提到以 24 fps 执行此操作,因此表明您正在处理视频。在这种情况下,你可以去掉中间人——视频帧已经在 GPU 上处理,将它们放在 CPU 上的 CGImages 只会减慢你的速度。查看CVOpenGLESTexture该类和GLCameraRipple示例代码,以帮助将视频转换为纹理。

于 2013-10-24T00:08:33.323 回答