知乎上看到一位大佬用 Shader 实现了 PPT 里面的转场效果,转载大佬的文章,一起围观膜拜一下。
原文分为上下两篇,详细阐述了每个效果的实现。
上篇:https://zhuanlan.zhihu.com/p/378967288
下篇:https://zhuanlan.zhihu.com/p/380968758
两篇文章实现了 PPT 里面大部分切换效果,如下图所示:
并且还提供了源码,除了两张转场图片之外,没有用到其他纹理,所有形状都是 shader 生成,并且没有开 FBO,保证单次 drawcall 完成。
源码地址如下:
https://github.com/ydc258ttbaby/PPT_transtions_with_shader
摘录了几个效果供大家参考:
擦除效果
现象:从右往左将上面一张图片擦除。
思路:主要还是依赖于 mix 函数进行混合,只不过在边缘处实现渐变,渐变的实现可简单用线性插值实现,如下图所示:
从右往左的擦除就好比将一条斜线从右往左移动,随后 clamp 就成为了透明度 alpha 。
代码:
void main()
{
vec4 texColor1 = texture(u_ourTexture1, texCoord);
vec4 texColor2 = texture(u_ourTexture2, texCoord);
float w = 0.5;
float alpha = clamp(-1.0 / w * texCoord.x + (1.0 + w) / w + u_ratio * (-(1.0 + w) / w), 0.0, 1.0);
FragColor = mix(texColor1, texColor2, alpha);
};
剥离效果
现象:一张图片像一张纸一样被揭开,显示出另一张图 。
要点:此实现类似于(十九-悬挂),假想有一根斜直线,如 y = x – 1,图片背面通过镜像得到,直线右边显示底图,左边显示上面的图。
代码实现:
// 斜直线对于 x 的表达式
float fx(float x)
{
return x - u_width + u_ratio * (u_height + u_width + 100.0);
}
// 斜直线对于 y 的表达式
float gy(float y)
{
return y + u_width - u_ratio * (u_height + u_width + 100.0);
}
void main()
{
vec4 resColor = vec4(u_ratio, 0.0, 0.0, 1.0);
vec4 texColor1 = texture(u_ourTexture1, texCoord);
vec4 texColor2 = texture(u_ourTexture2, texCoord);
// 转到画布真实的像素坐标系进行变换
vec2 coordRealScale = texCoord * vec2(u_width, u_height);
// 用二次函数,对揭开的边缘添加偏移
float xNor = (coordRealScale.x - gy(0.0)) / (u_width - gy(0.0));
float yNor = (coordRealScale.y - 0.0) / (fx(u_width) - 0.0);
if (coordRealScale.x > gy(0.0) && coordRealScale.x < u_width)
coordRealScale.y = coordRealScale.y + 70.0 * xNor * (1.0 - xNor);
if (coordRealScale.y > 0.0 && coordRealScale.y < fx(u_width))
coordRealScale.x = coordRealScale.x - 70.0 * yNor * (1.0 - yNor);
// 沿 y = f(x) 翻转
coordRealScale = vec2(gy(coordRealScale.y), fx(coordRealScale.x));
vec2 coord = coordRealScale / vec2(u_width, u_height);
// 添加光影变化
float intensityOffset = (1.0 - (1.0 - coord.x) * u_width / u_height - coord.y) + 2.0 * u_ratio - 0.1;
// 揭开的背面的部分
resColor = texture(u_ourTexture1, coord) * intensityOffset;
if (coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0)
resColor = texColor1;
if (coordRealScale.y > fx(coordRealScale.x))
resColor = texColor2;
FragColor = resColor;
};
这种剥离效果在其他地方也是可以用到的,很有参考意义。
关于其他更多的效果,欢迎到原作者的文章上去看,有着详细代码讲解和技术总结,受益匪浅~~