在抖音等常用的音视频软件中经常发现有分屏的滤镜效果,现在总结一下具体的VertexShader中,每个函数中的算法。
常规方法滤镜中的FragmentShader算法
vertexShader代码设置
attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;
void main (void) {
gl_Position = Position;
TextureCoordsVarying = TextureCoords;
}
其中Position是我们的物体坐标,TextureCoords是纹理坐标,TextureCoordsVarying是我们需要传递到FragmentShader中的纹理坐标值,下面是FragmentShader中的内容
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
void main (void) {
vec4 mask = texture2D(Texture, TextureCoordsVarying);
gl_FragColor = vec4(mask.rgb, 1.0);
}
需要注意的是在顶点着色其中的数据类型默认是有精度值得,但是在片元着色器中是没有设置精度的,所以我们需要为float设置精度precision highp float;
分析片元着色器中的赋值,首先根据纹理ID和纹理坐标获取纹理像素值mask,将mask进行4维向量转化,其目的是设置1.0的透明度,这里设置的不透明的,也可以直接将mask赋值给gl_FragColor,查看这样算法的效果。
二屏滤镜中的FragmentShader算法
我们默认是读取图片的中间部分,y轴方向是0.25-0.75,x轴方向0.0-1.0,所以我们在FragmentShader算法中进行修改。
precision highp float;
uniform sampler2D Texture;
varying highp vec2 TextureCoordsVarying;
void main() {
vec2 uv = TextureCoordsVarying.xy;
float y;
if (uv.y >= 0.0 && uv.y <= 0.5) {
y = uv.y + 0.25;
} else {
y = uv.y - 0.25;
}
gl_FragColor = texture2D(Texture, vec2(uv.x, y));
}
其中我们获取传递过来的纹理坐标的xy,然后对当前二维向量y值进行重新设置:
当y在uv.y >= 0.0 && uv.y <= 0.5,在y轴方向我们其实应该获取的是屏幕中间部分,所以y = uv.y + 0.25,将y方向上的纹理进行重新设置,读取从0.25 - 0.75的数据。
当0.5-1.0时,在y轴防线我们-0.25,获取从0.25 - 0.75的数据,效果如下。
三屏滤镜中的FragmentShader算法
我们默认是读取图片的中间1/3部分,y轴方向是1/3-2/3,x轴方向0.0-1.0,所以我们在FragmentShader算法中进行修改。
precision highp float;
uniform sampler2D Texture;
varying highp vec2 TextureCoordsVarying;
void main() {
vec2 uv = TextureCoordsVarying.xy;
if (uv.y < 1.0/3.0) {
uv.y = uv.y + 1.0/3.0;
} else if (uv.y > 2.0/3.0){
uv.y = uv.y - 1.0/3.0;
}
gl_FragColor = texture2D(Texture, uv);
}
其中我们获取传递过来的纹理坐标的xy,然后对当前二维向量y值进行重新设置:
当y在uv.y < 1.0/3.0,在y轴方向我们其实应该获取的是屏幕中间1/3部分,所以uv.y = uv.y + 1.0/3.0,将y方向上的纹理进行重新设置,读取从1/3 - 2/3的数据。
当uv.y > 2.0/3.0时,在y轴防线我们- 1.0/3.0,获取从1/3 - 2/3的数据,效果如下。
其他的区域默认是不变的。
效果如下
四屏滤镜中的FragmentShader算法
我们默认是将整张图片进行压缩,将这张压缩图放到屏幕均分的四个位置,所以我们在FragmentShader算法中进行修改。
precision highp float;
uniform sampler2D Texture;
varying highp vec2 TextureCoordsVarying;
void main() {
vec2 uv = TextureCoordsVarying.xy;
if(uv.x <= 0.5){
uv.x = uv.x * 2.0;
}else{
uv.x = (uv.x - 0.5) * 2.0;
}
if (uv.y<= 0.5) {
uv.y = uv.y * 2.0;
}else{
uv.y = (uv.y - 0.5) * 2.0;
}
gl_FragColor = texture2D(Texture, uv);
}
其中我们获取传递过来的纹理坐标的xy,然后对当前二维向量x和y值进行压缩之后重新设置:
在x方向,当uv.x <= 0.5,我们将原始的x进行放大2倍,那么新的x获取到的就是原始纹理2倍x出的纹理像素值;在0.5-1.0,我们需要将原始x-0.5,在进行放大2倍,这样我们就将x方向纹理像素值缩小后后放到了新的x位置;
同理y轴方向进行缩放;效果如下
六屏滤镜中的FragmentShader算法
我们默认是读取图片的中间矩形部分,y轴方向是1/3-2/3,x轴方向1/3-2/3,所以我们在FragmentShader算法中进行修改。
precision highp float;
uniform sampler2D Texture;
varying highp vec2 TextureCoordsVarying;
void main() {
vec2 uv = TextureCoordsVarying.xy;
if(uv.x <= 1.0 / 3.0){
uv.x = uv.x + 1.0/3.0;
}else if(uv.x >= 2.0/3.0){
uv.x = uv.x - 1.0/3.0;
}
if(uv.y <= 0.5){
uv.y = uv.y + 0.25;
}else {
uv.y = uv.y - 0.25;
}
gl_FragColor = texture2D(Texture, uv);
}
其中我们获取传递过来的纹理坐标的xy,然后对当前二维向量x、y值进行重新设置:
当x方向,在uv.x <= 1.0 / 3.0,我们获取的应该是从1/3开始的纹理,所以+1/3,在uv.x >= 2.0/3.0时,还是取1/3开始的纹理,所以应该-1/3;
在y轴方向,我们取0.25-0.75两部分,y轴展示时我们可以分成0-0.5和0.5-1.0两部分,所以当uv.y <= 0.5,应该+0.25,在其他位置-0.25;
效果如下
总结
我们只是提供了一种算法的思路,具体的业务变化需要我们灵活的变动相应的算法,来适应不同的业务需要