在 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)
函数基于a
在x
和y
之间进行插值。 a
of 0 给你所有x
,a
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