在 iOS 上的 OpenGL ES 着色器中混合多个纹理会导致反向行为

Posted

技术标签:

【中文标题】在 iOS 上的 OpenGL ES 着色器中混合多个纹理会导致反向行为【英文标题】:Mixing Multiple Textures in OpenGL ES Shader on iOS Results in Inverse Behavior 【发布时间】:2012-06-06 05:41:06 【问题描述】:

我有一个 OpenGL ES 着色器片段着色器,它使用混合功能在视频帧上放置一个叠加层。这是我的着色器:

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 textureCoordinate;

uniform sampler2D videoFrameY; 
uniform sampler2D videoFrameUV;
uniform sampler2D overlay;

const mat3 yuv2rgb = mat3(
                          1,        1,          1,
                          0,        -.21482,    2.12798,
                          1.28033,  -.38059,    0
                          );

void main() 
    
    vec3 yuv;
    vec4 ovr;
    
    yuv.x = texture2D(videoFrameY, textureCoordinate).r;
    yuv.yz = texture2D(videoFrameUV, textureCoordinate).rg - vec2(0.5, 0.5);
    ovr = texture2D(overlay, textureCoordinate);
    
    vec3 rgb = yuv2rgb * yuv;
    
    gl_FragColor = mix(ovr, vec4(rgb, 1.0), ovr.a);
 

没有覆盖纹理,喂gl_FragColor这个:

gl_FragColor = vec4(rgb, 1.0);

工作得很好,我的视频也显示出来了。现在我正在从CATextLayer 创建我的叠加纹理,如下所示:

- (void)generateOverlay 
    CATextLayer *textLayer = [CATextLayer layer];
    [textLayer setString:@"Sample test string"];
    [textLayer setFont:(__bridge CFStringRef)@"Helvetica"];
    [textLayer setFontSize:(_videoHeight / 6)];
    [textLayer setAlignmentMode:kCAAlignmentLeft];
    [textLayer setBounds:CGRectMake(0, 0, _videoWidth, _videoHeight)];
    
    CGSize layerSize = textLayer.bounds.size;
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    void *imageData = malloc(layerSize.height * layerSize.width * 4);
    CGContextRef context = CGBitmapContextCreate(imageData, layerSize.width, layerSize.height, 8, 4 * layerSize.width, colorspace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorspace);
    CGContextClearRect(context, CGRectMake(0, 0, layerSize.width, layerSize.height));
    CGContextTranslateCTM(context, 0, layerSize.height - layerSize.height);
    [textLayer renderInContext:context];
    
    glActiveTexture(GL_TEXTURE2);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layerSize.width, layerSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
    
    CGContextRelease(context);
    free(imageData);


问题是结果是相反的。因此它们看起来像这样:

(来源:c.tro.pe)

事实上,它们以两种方式倒置。首先,不是蓝色被 alpha'ed 和视频显示,文本是 alpha,这就是视频显示的地方。其次,文字是镜像的。镜像可能是使用顶点值的结果,但是视频使用相同的坐标是正确的。我确定这是一个快速的重新排列,但我不确定要调整什么。谢谢!

【问题讨论】:

【参考方案1】:

对于混合,mix(x, y, a) 函数基于axy 之间进行插值。 a of 0 给你所有xa of 1.0 给你所有y。您正在关闭文本图层的 alpha,因此对于您想要的叠加层,您需要按如下方式反转您的顺序:

gl_FragColor = mix(vec4(rgb, 1.0), ovr, ovr.a);

关于旋转,请记住 ios 后置摄像头横向安装在左侧,前置摄像头横向安装在右侧,因此对于纵向,您需要旋转传入的视频帧。您似乎在顶点或纹理坐标中执行该旋转。您将需要第二组未旋转的纹理坐标用于对叠加图像进行采样,或者您需要在生成其纹理时在匹配的横向左旋转处绘制标签。

【讨论】:

gl_FragColor 的变化就像一个魅力。一年过去了,我完全忘记了顶点和位置坐标是如何工作的。我知道我的四边形位置是 (-1,-1) (1,-1) (-1, 1) 和 (1,1)。暂时忘记文本层,对于横向右设备方向,我遇到了 s 和 d 纹理坐标的问题。他们以什么顺序绘制,所以我不会得到镜像?对于 (1,0) (0,0) (1,1) (0,1) 的 tex 坐标,我最终会得到一个在 X 和 Y 上都镜像的图像。我会担心带有仿射的文本层变换。 一切都好。我读了这个page。我只是在纸上画了出来,然后将 s & t 映射到相反的方向。现在我有 (0,1) (1,1) (0,0) (1,0) 并且视频在 X 和 Y 中都是正确的。至于文本,我将翻转上下文。

以上是关于在 iOS 上的 OpenGL ES 着色器中混合多个纹理会导致反向行为的主要内容,如果未能解决你的问题,请参考以下文章

Photoshop 混合模式到没有着色器的 OpenGL ES

OpenGL ES 上的图像几何重新映射

OpenGL ES 2.0中的剪切平面

使用 GL_TEXTURE_2D 的 iOS YUV 420v 在 OpenGL 着色器中显示错误的颜色

iOS上的OpenGL ES 1.1:没有剪裁平面?

在 OpenGL ES 中渲染“层”