持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
之前的文章中,我们使用 GLSL 自定义着色器 来显示了一张图片,今天我们来实现一下 二分屏、三分屏、四分屏、六分屏和九分屏这些 简单的滤镜效果。
之前Demo的调整
之前我们基于 SMView 来做的默认着色器程序的加载, 现在我们封装出来一个方法:
/// 加载着色器程序
/// - **Parameter** shaderName: 着色器文件名称
- (**void**)loadShaderWithName:(NSString *)shaderName;
方法的实现就是将,我们之前加载显示图片的六步拿过来(将开始绘制方法中读取顶点着色程序、 片源着色程序的部分改为外部传参指定文件即可):
- (**void**)loadShaderWithName:(NSString *)shaderName {
//1.设置图层
[**self** setupLayer];
//2.设置图形上下文
[**self** setupContext];
//3.清空缓存区
[**self** deleteRenderAndFrameBuffer];
//4.设置RenderBuffer
[**self** setupRenderBuffer];
//5.设置FrameBuffer
[**self** setupFrameBuffer];
//6.开始绘制
[**self** renderLayerWithName:shaderName];
}
好的,准备工作做好,我们就开始先分析下二分屏的效果如何做出来。
二分屏
我们要实现将红框中的内容展示在上下两个黑框中;
- 二分屏滤镜的显示内容我们要做到屏幕分为上下两个区域,也就是上图中的黑色框框分开的内容。
- 黑色框框显示的内容是图片红色区域框选出来的图片内容
上半个屏幕 在显示纹理坐标时,x坐标是不变的,y坐标会增加0.25; 下班个屏幕 在显示纹理坐标时,x坐标童谣不变,y坐标则是减小0.25; 所以:
我们的片元着色器修改为:
precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
vec2 zb = varyTextCoord.xy;
if (varyTextCoord.y >= 0.0 && varyTextCoord.y <= 0.5) {
zb.y = varyTextCoord.y + 0.25;
}else {
zb.y = varyTextCoord.y - 0.25;
}
gl_FragColor = texture2D(colorMap, zb);
}
三分屏
原理上和二分屏类似的效果 只不过是 按照 三分之一来 分配屏幕;
precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
vec2 zb = varyTextCoord.xy;
float fp = 1.0 / 3.0;
if ( zb.y >= 0.0 && zb.y < fp ) {
zb.y = zb.y + fp;
}else if ( zb.y > 2.0/3.0 && zb.y <= 1.0 ) {
zb.y = zb.y - fp;
}
gl_FragColor = texture2D(colorMap, zb);
}
四分屏
四分屏则会同时修改纹理坐标的x值和y值
- 首先分析x值,从0 - 0.5 要映射为 0 - 1.0 才可以把整个图片原来的内容展示全,所以 需要 将 x * 2.0;
- 第二, 从0.5 - 1.0 ,同样要映射为 0 - 1.0 , 所以 需要 进行 运算 (x - 0.5)* 2;
- y值的变化 同 x值的变化;
所以片元着色器的代码为:
precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
vec2 zb = varyTextCoord.xy;
if ( zb.x >= 0.0 && zb.x < 0.5 ) {
zb.x = zb.x * 2.0;
}else if ( zb.x >= 0.5 && zb.x <= 1.0 ) {
zb.x = (zb.x - 0.5) * 2.0;
}
if ( zb.y >= 0.0 && zb.y < 0.5 ) {
zb.y = zb.y * 2.0;
}else if ( zb.y >= 0.5 && zb.y <= 1.0 ) {
zb.y = (zb.y - 0.5) * 2.0;
}
gl_FragColor = texture2D(colorMap, zb);
}
六分屏
六分屏我们要实现 将 红框中的内容,展示在 六个区域中;
通过观察,可以发现:
- x坐标 在 1.0/3.0 - 2.0/3.0 之间是不需要做变化的;
- 小于1.0/3.0 是 纹理坐标+1.0/3.0;
- 大于2.0/3.0时,x坐标 - 1.0/3.0;
- y坐标,在小于0.5时, y坐标+0.25;
- 大于0.5时,y坐标 -0.25;
所以片元着色器的代码如下:
precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
vec2 zb = varyTextCoord.xy;
if ( zb.x >= 0.0 && zb.x < 1.0/3.0 ) {
zb.x = zb.x + 1.0/ 3.0;
}else if ( zb.x >= 1.0/3.0 && zb.x <= 2.0/3.0 ) {
}else if ( zb.x >= 2.0/3.0 && zb.x <= 1.0 ) {
zb.x = zb.x - 1.0/3.0;
}
if ( zb.y >= 0.0 && zb.y < 0.5 ) {
zb.y = zb.y + 0.25;
}else if ( zb.y >= 0.5 && zb.y <= 1.0 ) {
zb.y = zb.y - 0.25;
}
gl_FragColor = texture2D(colorMap, zb);
}
九分屏
有了六分屏和四分屏的经验,我们的九分屏九比较简单了;先看下九分屏要实现的效果吧:
x 坐标和 y 坐标 的变化 都是要分 1。0/3.0 和 2.0/3.0 分割的三部分。 偏远着色器的代码为:
precision highp float;
varying highp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
vec2 zb = varyTextCoord.xy;
if ( zb.x >= 0.0 && zb.x < 1.0/3.0 ) {
zb.x = zb.x * 3.0;
}else if ( zb.x >= 1.0/3.0 && zb.x <= 2.0/3.0 ) {
zb.x = (zb.x - 1.0/3.0) * 3.0;
}else if ( zb.x >= 2.0/3.0 && zb.x <= 1.0 ) {
zb.x = (zb.x - 2.0/3.0) * 3.0;
}
if ( zb.y >= 0.0 && zb.y < 1.0/3.0 ) {
zb.y = zb.y * 3.0;
}else if ( zb.y >= 1.0/3.0 && zb.y <= 2.0/3.0 ) {
zb.y = (zb.y - 1.0/3.0) * 3.0;
}else if ( zb.y >= 2.0/3.0 && zb.y <= 1.0 ) {
zb.y = (zb.y - 2.0/3.0) * 3.0;
}
gl_FragColor = texture2D(colorMap, zb);
}
最后,我们看下整体的效果吧