本文案例代码有OC及Swift版本,详情见文末链接
本案例的目的是理解如何用GLSL实现分屏(2/3/4/6/9)滤镜
案例的效果图如下
完成无分屏滤镜的着色器代码
attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;
void main(){
gl_Position = Position;
TextureCoordsVarying = TextureCoords;
}
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;
void main(){
vec4 mask = texture2D(Texture, TextureCoordsVarying);
gl_FragColor = vec4(mask.rgb, 1.0);
}
在实现分屏滤镜之前,首先要呈现一个最原始的图片,即无滤镜效果的图片,大致流程如下
主要分为3部分
主要是添加自定义的滤镜滚动条,利用collectionView实现底部自定义滚动视图,这部分内容不多做说明,如果有疑问,可以参考文末完整demo
根据图示,分为以下几部分
设置视口
以上几部分的代码,在之前的OpenGL ES案例中均有涉及,这里这不展开说明了,详情可以参考文末完整代码
分屏滤镜的实现主要还是分屏算法,而分屏算法主要是在片元着色器中main函数中完成的,所以切换不同分屏效果主要需要改动以下几部分内容
setupNormalShaderProgram函数
,只需要修改着色器文件的名称即可下面分别说明下不同分屏效果的分屏算法的实现
当实现二分屏滤镜时,图片纹理坐标的x值是没有任何变化的,主要是y值变化
片元着色器中main函数的分屏算法代码如下
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));
}
三分屏的显示是屏幕三等分,分别显示图片中部分三分之一图片,其实现原理如下
当实现三分屏滤镜时,图片纹理坐标的x值是没有任何变化的,主要是y值变化
片元着色器中main函数的分屏算法代码如下
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);
}
四分屏的显示是屏幕四等分,分别显示缩小的纹理图片,其实现原理如下
纹理图片与屏幕的映射既可以是一致的坐标,也可以映射到缩小的坐标,如上图所示。
当实现四分屏时,纹理坐标x、y均需要变化,且屏幕坐标需要与纹理坐标一一映射,例如(x,y)取值(0.5,0.5)需要映射到纹理坐标(1,1)时,x、y均需要乘以2,即0.5 * 2 = 1,变化规则如下:
片元着色器中main函数的分屏算法代码如下
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);
}
当实现六分屏时,纹理坐标x、y均需要变化,其变化规则如下:
片元着色器中main函数的分屏算法代码如下
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);
}
当实现九分屏时,纹理坐标x、y均需要变化,其变化规则如下:
片元着色器中main函数的分屏算法代码如下
void main(){
vec2 uv = TextureCoordsVarying.xy;
if (uv.x <= 1.0/3.0) {
uv.x = uv.x * 3.0;
}else if (uv.x >= 2.0/3.0){
uv.x = (uv.x - 2.0/3.0) * 3.0;
}else{
uv.x = (uv.x - 1.0/3.0)*3.0;
}
if (uv.y <= 1.0/3.0) {
uv.y = uv.y * 3.0;
}else if (uv.y >= 2.0/3.0){
uv.y = (uv.y - 2.0/3.0) * 3.0;
}else{
uv.y = (uv.y - 1.0/3.0)*3.0;
}
gl_FragColor = texture2D(Texture, uv);
}
完整的代码见Github - 13_分屏滤镜_OC、13_分屏滤镜_Swift