这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
前面我们介绍了一些很酷炫的特效,比如
蓝线挑战和传送带特效,不过对于初学者来说,难度较大,故,本章将介绍一些简单但有趣的特效
一、Shader特效
对于OpenGLES的开发来说,最难的部分还是着色器,无论是顶点着色器,还是片元着色器,都是OpenGLES开发的重点,当然,这两者中,片元着色器的使用几率更高点
为什么要对着色器进行处理?
因为做特效,最重要的就是对其像素进行一系列操作,从而完成想要的效果,比如,
我想让一张图片灰度化,那么就得操作其像素
我想让一张图片分屏,那么也得操作其像素
。。。
特效分为几种
禁止的,具有固定的形态动态的,会随着时间的流逝而运动
前面我们介绍的蓝线挑战和传送带特效,都属于动态的
下面,我们将介绍几款静态的特效
二、特效分析和展示
下面所展示的特效,基本上只修改了片元着色器,顶点着色器是固定的,如下所示:
顶点着色器
attribute vec4 aPos;
attribute vec2 aCoordinate;
varying vec2 vCoordinate;
void main(){
vCoordinate = aCoordinate;
gl_Position = aPos;
}
2.1. 灰度图
让画面变灰以下有几种方法:
- 取
R、G、B三者的平均值 - 取
R、G、B任一值当做共同值 - 取
R、G、B做加权平均当做共同值
三种方法都可以使图片变灰,这里我采用了第三种
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
const vec3 GRAY = vec3(0.299, 0.587, 0.144);
void main(){
vec4 sourceColor = texture2D(uSampler, vCoordinate);
float gray =dot(sourceColor.rgb, GRAY);
gl_FragColor = vec4(gray, gray, gray, sourceColor.a);
}
注意到,在片元着色器中,使用当前像素值与vec3(0.299, 0.587, 0.144)进行向量的点积操作,即
效果如下:
2.2 两分屏
对于分屏特效,我只需要对其纹理坐标进行处理即可
两分屏,则是将屏幕分为两半,且两半显示的内容的一半,那么这两半屏幕的内容显示的是哪个区域内?
所以,我们只需要搞懂显示的区域即可得到对应的效果
当然,你可以随意显示想要显示的区域,不过有一点需要注意,就是一半屏幕的宽或者高是0 ~ 0.5,所有你能显示的区域的范围只能是0.5,超过或者小于,则会造成画面拉伸或压缩
下面的片元着色器显示的是0.25 ~ 0.75之间的区域
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main(){
if (vCoordinate.y < 0.5) {
gl_FragColor = texture2D(uSampler, vCoordinate + vec2(0.0, 0.25));
} else {
gl_FragColor = texture2D(uSampler, vCoordinate - vec2(0.0, 0.25));
}
}
效果如下:
2.3 三分屏
对于两分屏的原理搞懂了,那么三分屏自然不在话下
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main(){
if (vCoordinate.y < 0.33) {
gl_FragColor = texture2D(uSampler, vCoordinate + vec2(0.0, 0.33));
} else if (vCoordinate.y > 0.66){
gl_FragColor = texture2D(uSampler, vCoordinate - vec2(0.0, 0.33));
} else {
gl_FragColor = texture2D(uSampler, vCoordinate);
}
}
效果如下:
2.4 四分屏
片元着色器
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main(){
float x = vCoordinate.x;
float y = vCoordinate.y;
if (x < 0.5) {
x *= 2.0;
} else {
x = (x - 0.5) * 2.0;
}
if (y < 0.5) {
y *= 2.0;
} else {
y = (y - 0.5) * 2.0;
}
gl_FragColor = texture2D(uSampler, vec2(x, y));
}
效果如下:
2.5 九分屏
片元着色器
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vCoordinate;
void main(){
float x = vCoordinate.x;
float y = vCoordinate.y;
if (x < 0.33) {
x *= 3.0;
} else if (x < 0.66) {
x = (x - 0.33) * 3.0;
} else {
x = (x - 0.66) * 3.0;
}
if (y < 0.33) {
y *= 3.0;
} else if (y < 0.66) {
y = (y - 0.33) * 3.0;
} else {
y = (y - 0.66) * 3.0;
}
gl_FragColor = texture2D(uSampler, vec2(x, y));
}
效果如下:
对于分屏的逻辑,可能存在效率问题,因为用到了比较多的if-else,不过这里就当是参考,实际使用时可以考虑优化这部分的逻辑
2.6 画中画
我们在之前的高斯模糊与毛玻璃那一章介绍了高斯模糊的原理,并讲解了它的一个使用特效毛玻璃,那么接下来我们将使用毛玻璃的效果制作一个画中画的特效
首先实现的效果:
可以看到:
- 画面中心是清晰的图像
- 上下两个部分是毛玻璃效果、且放大了的图像
那么就可以知道,画中画特效其实是有两张纹理组成,一张是原图像,另一张是放大且添加毛玻璃效果的图像
具体的代码比较多,且涉及到Fbo,这里就不贴出来了
感兴趣的可以到GitHub上查看