[经验总结]部分复杂效果的优化方法和思路

简介:

在效果开发过程中,我们会遇到各种问题导致所开发的效果性能不尽人意,不同效果的针对优化策略不同,这里就不过于赘述,选取两个比较典型的较为复杂和消耗性能的效果,毛玻璃马赛克和磨砂玻璃马赛克效果进行举例优化

一.毛玻璃效果

该效果实现如下,实现具体原理这里不描述,有兴趣的读者可以私信,可以写一篇关于这种效果的实现 


precision highp float;
 varying vec2 texcoordOut;
 uniform sampler2D texSampler;
 
 const float pi = 3.1415926

 // 生成具有周期性的2D向量噪声
 vec2 hash( vec2 p ) { p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))); return fract(sin(p)*18.5453); }

 // 使用 Worley noise 方法生成基于网格的2D噪声
 float simplegridnoise(vec2 v)
 {
     float s = 1. / 256.;
     vec2 fl = floor(v), fr = fract(v);
     float mindist = 1e9;
     for(int y = -1; y <= 1; y++)
         for(int x = -1; x <= 1; x++)
         {
             vec2 offset = vec2(x, y);
             vec2 pos = .5 + .5 * cos(2. * pi * (1.0*.1 + hash(fl+offset)) + vec2(0,1.6));
             mindist = min(mindist, length(pos+offset -fr));
         }
     
     return mindist;
 }

 // 生成更平滑的噪声效果,通过控制s参数可以调整噪声的尖锐程度
 float blobnoise(vec2 v, float s)
 {
     return pow(.5 + .5 * cos(pi * clamp(simplegridnoise(v)*2., 0., 1.)), s);
 }

 // 生成带有噪声的法线向量。这用于在纹理扰动中增强光照效果
 vec3 blobnoisenrm(vec2 v, float s)
 {
     vec2 e = vec2(.01,0);
     return normalize(
            vec3(blobnoise(v + e.xy, s) - blobnoise(v -e.xy, s),
                 blobnoise(v + e.yx, s) - blobnoise(v -e.yx, s),
                 1.0));
 }
 
// 一种组合方法,根据多次运算的结果生成更自然和复杂的噪声效果
 float blobnoises(vec2 uv, float s)
 {
     float h = 0.0;
     const float n = 3.0;
     for(float i = 0.0; i < n; i++)
     {
         vec2 p = vec2(0.0, 1.0 * 1.0 * (i + 1.0) / n) + 1.0 * uv;
         h += pow(0.5 + 0.5 * cos(pi * clamp(simplegridnoise(p * (i + 1.0)) * 2.0, 0.0, 1.0)), s);
    }
     
     return h / n;
 }


// 针对组合噪声效果的法线生成方法
 vec3 blobnoisenrms(vec2 uv, float s)
 {
     float d = 0.01;
     return normalize(
            vec3(blobnoises(uv + vec2(  d, 0.0), s) - blobnoises(uv + vec2( -d, 0.0), s),
                 blobnoises(uv + vec2(0.0,   d), s) - blobnoises(uv + vec2(0.0,  -d), s),
                 d));
 }
 
 void main() {
     vec2 uv = texcoordOut;
     vec3 n = blobnoisenrms(55.0 * uv, 1.);
     gl_FragColor = texture2D(texSampler, uv + 0.01 * n.xy);
 } ;

 分析:其实不难看出,几乎所有都操作都是在计算坐标,而没有对 rgb 值进行修改,分析得出卡顿的原因是由于计算次数过多,导致性能受到影响,而由于原图的坐标是固定的,因此这些计算其实是可以避免的因此有以下两种方案:

        1.我们只需要再使用一个着色器,先对这些坐标进行一次计算,然后以 framebuffer 的形式保存,执行效果的时候每次传入计算好的坐标,即可省去大量重复的计算

        2.采取空间换时间,直接在外部计算好这些坐标,生成一张纹理图,这样就可以省去所有计算次数

    对比之后发现,1.2 两种方法在相同情况下的时间消耗差别不大,2 会略胜 1,但是直接使用生成的纹理图不仅会增加空间成本,还会由于高画质和屏幕适配比问题导致效果收到一定影响,因此考虑选用方案一,优化如下:

1.先对该效果进行预处理,保存需要处理的坐标:

    varying vec2 texcoordOut;
    uniform sampler2D texture;

    const float pi = 3.1415926;

    vec2 hash( vec2 p ) 
    {         
        p=vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))); 
        return fract(sin(p)*18.5453); 
    }

    float simplegridnoise(vec2 v)
    {
        float s = 1. / 256.;
        vec2 fl = floor(v);
        vec2 fr = fract(v);
        float mindist = 1e9;
        for(int y = -1; y <= 1; y++)
            for(int x = -1; x <= 1; x++)
            {
                vec2 offset = vec2(x, y);
                vec2 pos = .5 + .5 * cos(2. * pi * (1.0*.1 + hash(fl+offset)) + vec2(0,1.6));
                mindist = min(mindist, length(pos+offset -fr));
            }

        return mindist;
    }

    float blobnoise(vec2 v, float s)
    {
        return pow(.5 + .5 * cos(pi * clamp(simplegridnoise(v)*2., 0., 1.)), s);
    }

    vec3 blobnoisenrm(vec2 v, float s)
    {
        vec2 e = vec2(.01,0);
        return normalize(vec3(blobnoise(v + e.xy, s) - blobnoise(v -e.xy, s),blobnoise(v + e.yx, s) - blobnoise(v -e.yx, s),1.0));
    }

    float blobnoises(vec2 uv, float s)
    {
        float h = 0.0;
        const float n = 3.0;
        for(float i = 0.0; i < n; i++)
        {
            vec2 p = vec2(0.0, 1.0 * 1.0 * (i + 1.0) / n) + 1.0 * uv;
            h += pow(0.5 + 0.5 * cos(pi * clamp(simplegridnoise(p * (i + 1.0)) * 2.0, 0.0, 1.0)), s);
        }

        return h / n;
    }

    vec3 blobnoisenrms(vec2 uv, float s)
    {
        float d = 0.01;
        return normalize(
        vec3(blobnoises(uv + vec2(  d, 0.0), s) - blobnoises(uv + vec2( -d, 0.0), s),blobnoises(uv + vec2(0.0,   d), s) - blobnoises(uv + vec2(0.0,  -d), s),d));
    }
    void main() {
        vec4 temp = texture2D(texture,texcoordOut);
        vec2 uv = texcoordOut;
        vec3 n = blobnoisenrms(55.0 * uv, 1.);
        gl_FragColor = vec4(n,1.0);
    }

2.然后将该坐标保存成纹理,再做效果


    varying vec2 texcoordOut;
                                                                           
    uniform sampler2D texture;
    uniform sampler2D texture1;
    void main() {
        vec2 uv = texcoordOut;
        vec3 n = texture2D(texture1,texcoordOut).rgb;//计算好的坐标
        gl_FragColor =vec4(texture2D(texture, uv + 0.01 * n.xy).rgb, 1.0);
    }

经测试,该效果在 4k的分辨率的图片下,性能提升能达到 10倍以上,2k 情况下能达到 500%

二.磨砂玻璃效果:

 该效果实现 shader 如下:

precision highp float;
varying vec2 texcoordOut;
uniform sampler2D texture;
uniform float width;
uniform float height;

void main()
{
    float one_inv_width = 1.0/width;
    float one_inv_height = 1.0/height;
    vec4 textureColor = texture2D(texture, texcoordOut);
    float this_weight = (textureColor.r + textureColor.g + textureColor.b) / 3.0;
    vec4 total_color = vec4(0.0);
    float total_weight = 0.0;
    int radius = 3;
    int radius_2 = 7;//radius*2 + 1
    float i = 0.0;
    float j = 0.0;
    for(int k=0; k<49; k++)
    {
        i = floor(float(k)/7.0);
        j = float(k) - i*7.0;
        i -= float(3.0);
        j -= float(3.0);
        vec2 coord = texcoordOut + vec2(float(i)*one_inv_width, float(j)*one_inv_height);
        vec4 color = texture2D(texture, coord);
        float weight= exp((i*i + j*j));
        total_color += color * weight;
        total_weight += weight;
    }
    gl_FragColor = total_color/total_weight;
}


    分析:通过查看着色器,我们可以发现,其实着色器内容并不是很多,在思考后,发现着色器内部可优化的空间较小,每次计算都是有意义的,只能考虑改进 for 循环的次数,或者合并部分计算公式,但是尝试后发现优化效果都不明显,优化幅度只能达到 3%-5%,再次分析卡顿原因,发现应该是导入的图片 size 过大,导致需要计算的像素点过多,计算次数量大,当几个相同效果叠加时,会导致卡顿,由于效果是马赛克,原图作用后是有模糊感的,于是考虑 针对性优化,当画质较高的时候,可以采用压缩 framebuffer,当采用当画质大于 2K时,将原图绘制在 压缩后的 buffrer上,这样即可在牺牲小部分效果的情况下,换区极大幅度的性能提升

总结:

  本文简单描述了针对部分较为复杂的效果,针对其实现方式和原理,我们可以使用不同的方法和思路进行优化,这仅仅只是针对 2.0 的效果,对于一些外部内部优化空间都小的情况,在设备支持的情况下,我们可以使用 OPENGL3.0,并使用GLSL3.0语法代替 ,3.0 具有很多特性(比如inout,MRT 等),这里只介绍两个基本优化思路,后续读者有兴趣,我写一篇 GL3.0的文章分享给大家

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值