【问题标题】:GLKit masking or blending 2 textures both from jpegs no alphasGLKit掩盖或混合来自jpegs的2个纹理没有alphas
【发布时间】:2013-10-23 19:16:49
【问题描述】:

我正在使用 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。

我试过this masking approach 没有成功。

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

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

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

【问题讨论】:

    标签: ios iphone objective-c core-graphics glkit


    【解决方案1】:

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

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

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

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

    1. 将顶点从您用于glDraw 命令的坐标空间转换到剪辑空间。对于 2D 的东西,这很容易,因为您可以使用与 GLKBaseEffecttransform 属性相同的矩阵设置。
    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 示例代码,以帮助将视频转换为纹理。

    【讨论】:

    • 感谢您的回答。我一定会根据您在此处提供的新信息对此进行进一步调查。至于您对 GLCameraRipple 的最后评论,此应用程序从摄像头获取视频源。这也可能来自视频文件吗?再次感谢。
    • 该示例代码从相机捕获所涉及的AVCaptureOutput 提供的示例缓冲区创建CVOpenGLESTextures。您还可以使用AVAssetReader 从文件中获取样本缓冲区。不过,这方面的细节将成为一个单独问题的素材。
    猜你喜欢
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多