传送带特效
通过仔细观察抖音的传送带特效,你可以发现左侧是不停地更新预览画面,右侧看起来就是一小格一小格的竖条状图像区域不断地向右移动,一直移动到右侧边界位置。
抖音传送带特效原理
预览的时候每次拷贝一小块预览区域的图像送到传送带,这就形成了源源不断地向右传送的效果。
这种实现方式会有什么问题呢?
从上面的文章可以看出,它使用的是 CPU 内存来作为缓存,然后每次绘制之前都需要进行一系列的拷贝,最后再上传数据到纹理。
由于每帧都需要进行拷贝和上传数据的操作,在遇到分辨率比较高的图像时,造成性能和功耗上的开销很大。
优化的思路就是要减少数据拷贝和传输,使用纹理作为缓存,需要使用2个纹理作为缓存,一个纹理作为输入缓存,另一个作为输出缓存,每次绘制时2个纹理进行交换,这个需要配合帧缓冲区来使用,需要做离屏渲染。
如果你对帧缓冲区使用不太了解,可以参考文章:
如果对上面的思路还是不太明白的话,我画了一张图给你。
如图所示,input 表示输入纹理,buffer1表示保存上一次渲染结果的纹理,在 shader 中做一下偏移采样,然后和 input 拼成一张图,渲染结果保存到 buffer2 纹理,然后 buffer2 纹理作为下一次渲染的 buffer1,最后重复这个过程。
偏移采样和拼图的 shader:
precision highp float;
varying highp vec2 vTextureCoord;
uniform lowp sampler2D sTexture;//输入纹理
uniform lowp sampler2D sTexture2;//buffer 纹理
uniform highp vec2 inputSize;
void main() {
vec2 uv = vTextureCoord;
vec4 color = texture2D(sTexture, uv);//输入采样
float offset = 10.0;
uv.x -= offset * 1.0 / inputSize.x;//每次向右移动10个像素
vec4 bufferCol = texture2D(sTexture2, uv);//buffer texture 采样
float mask_val = step(uv.x, 0.5);
gl_FragColor = mix(bufferCol, color, mask_val);//左右两边图像拼接在一起
}
实测 4K 视频毫无压力:
-- END --