WebGl简单实践-烧灼纸张效果[转]

前言

最近想实现个酷炫的转场特效,想到了这个烧灼效果。最初想用svg滤镜实现,但动画效果非常卡,遂转而考虑使用webgl的片段着色器实现。下面是最终实现的效果

本文只关注片元着色器,WebGL基础知识可见一下链接:

WebGL 基础概念​webglfundamentals.orgWebGl简单实践-烧灼纸张效果[转]

 

画出烧焦的洞

我们使用放射渐变来实现,然后把中间不透明度为1的区域变成完全透明的。

放射渐变的实现非常简单,各像素的颜色仅需要通其到渐变中心的距离确定。

代码

float circle(vec2 st, vec2 center){
    return distance(st , center)*3.;
}

void main(){
    vec2 st = gl_FragCoord.xy / u_resolution;
    float color = circle(st , vec2(.5,.5));
    vec4 grandColor = mix(vec4(0. ,0. ,0. ,1.) , vec4(1.,1.,1.,0.) , smoothstep(.58 , .9 , color));

    if(grandColor.a == 1.)grandColor.a = 0.;
    gl_FragColor = grandColor;
}

效果

WebGl简单实践-烧灼纸张效果[转]

 

为烧焦的洞添加火焰边缘和熏黄效果

因为基本图形是使用放射渐变制作的,它的不透明度alpha从中间到周围由1渐变为0,所以我们可以利用渐变的值确定各部分位置,比如alpha在0.~.99间是纸张烧焦部分 ,在.99~1.间是火焰的位置,为1.时是中间烧掉的洞。烧焦部分由黑色到黄色的渐变效果,同样可以用alpha值作为度量。

代码

if(grandColor.a == 1.)grandColor.a = 0.;
else if(grandColor.a > .994 && grandColor.a <1.){
    grandColor = mix( vec4( 0.985,0.0,0.000 ,1.) , vec4(0.985,0.696,0.285 , 1.) , smoothstep(.994, .999 , grandColor.a) );
}
else{
    grandColor = vec4( mix(vec3(0.,0.,0.) , vec3(0.690,0.373,0.000 )  ,smoothstep(.23 , .55,1.- grandColor.a)) , grandColor.a*1.6);
}

WebGl简单实践-烧灼纸张效果[转]

 

制作不规则效果

上面的效果看起来完全不像一个烧焦的洞,它太规则了,为了得到形状更加自然的焦洞,可以使用一种名为柏林噪音(Perlin Noise)的技术。柏林噪音是一种梯度噪音,它的主要原理是在网格的顶点计算出随机的梯度,而后利用插值的方式利用周围顶点的梯度计算各点的噪声值。

这是柏林噪声的实现代码:

vec2 g_random(vec2 ip){
    return fract(sin(
        vec2(dot(ip,vec2(127.1,311.7)), dot(ip,vec2(269.5,183.3)))
    )* 44753.976967) *2. - 1.;
}

float g_noise(vec2 st){
    vec2 ip = floor(st);
    vec2 fp = fract(st);

    vec2 u = fp*fp*fp*(fp*(fp*6.-15.)+10.);//使用三次多项式进行插值
    return mix(
        mix(dot(g_random(ip) , fp-vec2(0.,0.)) , dot(g_random(ip+vec2(1.,0.)) , fp-vec2(1.,0.)) ,u.x),
        mix(dot(g_random(ip+vec2(0.,1.)) , fp-vec2(0.,1.)) , dot(g_random(ip+vec2(1.,1.)) ,fp-vec2(1.,1.)) , u.x),
        u.y
    );
}

在主函数中的相关代码:

vec2 copy = st;
copy *= vec2(4.,4.);
copy += g_noise(copy*3.);

//将放射渐变用噪声扭曲
color += (g_noise(copy) -.5)*.19;

效果

WebGl简单实践-烧灼纸张效果[转]

 

添加纹理

这下看起来好多了,不过还是有些奇怪——熏黄的部分颜色太平滑了,一般的纸张可不会这么光滑,最好再添加一点纹理。这里我们使用简单的噪声来实现

grandColor.a += (random(st*400.)-.5)*.2;

效果

WebGl简单实践-烧灼纸张效果[转]

 

动态效果

动态的实现非常简单,只要在着色器中添加时间的uniform即可。

 

完整代码:

BokunoMasayume/amazing-animation​github.comWebGl简单实践-烧灼纸张效果[转]

 

发布于 2019-07-08 WebGL       前端开发      Canvas

 

上一篇:cocos2d-x math之vec2封装


下一篇:在bigemap中 ArcGIS教程之DEM(高程)的应用(坡度坡向、提等高线)