Как я могу оптимизировать производительность этой SVG-анимации? - PullRequest
1 голос
/ 28 мая 2020

Я работаю над SVG-анимацией, вот ручка кода , чтобы проверить это. Он использует комбинацию фильтров SVG, масок SVG и анимации пути.

Проблема, с которой я столкнулся, заключается в том, что я изо всех сил пытаюсь заставить его работать на всех устройствах. На хорошем настольном компьютере с графическим процессором solid он отлично работает с приемлемым FPS. На умеренных ноутбуках он работает примерно со скоростью 12 кадров в секунду, а на большинстве базовых c устройств он работает до 2 кадров в секунду.

Я пробовал много разных вещей для повышения производительности, включая:

  • Пытаюсь убрать необходимость в перерисовке страницы . Но из того, что я обнаружил, невозможно анимировать путь без перерисовки.
  • Использование анимации SVG вместо CSS анимации. Но стало намного хуже.
  • Уменьшение количества слоев. Это улучшило производительность, но не полностью и изменило эстетику c.
  • Удаление фильтра тени. Это улучшило производительность, но не полностью и изменило эстетику. c.
  • Перемещение слоев в более сгруппированные, чтобы липкий фильтр применялся только один раз. Это улучшило производительность, но не было возможности сохранить тень между слоями.

Мы долго работали над этим, пытаясь заставить этот эффект работать эффективно на всех устройствах, и очень ценю любые идеи, которые у вас были :)

.full-screen {
    position: fixed;
    top: 0px; left: 0px;
    width: 100%; height: 100%;
}

.svg__container {
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
}

.svg-container {
    width: 2320px;
    height: 1600px;
    position: relative;
    top: 50%; left: 50%;
    transform: translate(-38%, -49%) scale(0.4);
}

.mask__area {
    fill: white;
}

.gooey-filter {
    filter: url(#gooey-filter);
}

.drop-shadow {
    filter: url(#drop-shadow-filter);
    opacity: 0.3;
    transform: translate(30px, 30px);
}

.layer1-main {
    will-change: d;
    animation: layer1-main__animation 15s ease-in-out infinite alternate;
}

.layer1-small {
    will-change: d;
    animation: layer1-mini__animation 15s ease-in-out infinite alternate;
}

.layer2-main {
    will-change: d;
    animation: layer2-main__animation 13s ease-in-out infinite alternate;
}

.layer2-small {
    will-change: d;
    animation: layer2-mini__animation 13s ease-in-out infinite alternate;
}

.layer3 {
    will-change: d;
    animation: layer3__animation 11s ease-in-out infinite alternate;
}

.layer4 {
    will-change: d;
    animation: layer4__animation 9s ease-in-out infinite alternate;
}


@keyframes layer1-main__animation {
    0% {
        d: path("m144.81109,43.71449c27.41462,-22.10974 62.89021,-29.31703 106.8048,-28.65849c43.91459,0.65854 76.29263,18.13413 129.39015,35.84144c53.09752,17.70731 128.73155,28.86581 136.35349,95.4999c7.62194,66.63409 -4.98773,66.60971 -21.08527,114.13407c-16.09754,47.52437 -22.37806,57.25605 -49.74391,81.15847c-27.36584,23.90242 -108.36579,32.30483 -192.75592,18.56094c-84.39013,-13.74388 -155.2834,-68.88713 -167.102,-104.11269c-11.8186,-35.22556 -18.1033,-112.09064 1.46966,-148.47019c19.57297,-36.37954 29.25438,-41.84371 56.669,-63.95345z");
    }
    50% {
        d: path("m157.61597,54.6901c24.36584,-28.2073 43.98777,-36.6341 81.8048,-37.80483c37.81703,-1.17073 86.04873,21.79266 139.14625,39.49997c53.09752,17.70731 145.19496,20.93899 155.86568,87.57308c10.67072,66.63409 -58.03651,61.1219 -68.03649,101.32919c-9.99998,40.20729 -3.47562,52.98775 -22.30488,83.59749c-18.82926,30.60973 -81.53653,65.23166 -193.97544,45.99997c-112.43892,-19.23169 -178.45413,-97.54567 -180.51663,-152.89318c-2.0625,-55.34751 34.94548,-68.79795 50.25015,-101.51897c15.30467,-32.72101 13.40072,-37.57542 37.76656,-65.78272z");
    }
    100% {
        d: path("m147.25012,63.22668c13.99999,-21.49998 38.49997,-46.99995 93.99992,-49.99995c55.49995,-3 57.99995,28.49998 104.99991,39.49997c46.99996,10.99999 182.99984,18.49998 195.49983,95.49991c12.49999,76.99994 -74.49993,65.99995 -84.49991,99.49992c-9.99999,33.49997 7.49999,47.49995 -9.5,77.49993c-16.99999,29.99998 -72.99994,69.49995 -207.99983,45.99997c-134.99989,-23.49999 -176.62486,-99.37494 -178.68736,-148.62489c-2.0625,-49.24995 47.1406,-66.96868 62.44527,-96.03116c15.30467,-29.06248 9.74218,-41.84372 23.74217,-63.3437z");
    }
}

@keyframes layer1-mini__animation {
    0% {
        d: path("m152.67701,106.22571c18.49997,-3.37805 33.67071,11.99999 35.49998,34.99997c1.82927,22.99998 -17.2317,37.49997 -35.49998,36.99997c-18.26828,-0.5 -31.56096,-11.32925 -32.56095,-33.32924c-0.99999,-21.99999 14.06098,-35.29265 32.56095,-38.6707z");
    }
    50% {
        d: path("m69.75018,70.25011c18.49997,1.5 35.49998,11.99999 35.49998,34.99997c0,22.99998 -21.49999,37.49997 -35.49998,36.99997c-13.99999,-0.5 -33.99998,-9.49998 -34.99997,-31.49997c-0.99999,-21.99999 16.5,-41.99997 34.99997,-40.49997z");
    }
    100% {
        d: path("m69.75018,70.25011c18.49997,1.5 35.49998,11.99999 35.49998,34.99997c0,22.99998 -21.49999,37.49997 -35.49998,36.99997c-13.99999,-0.5 -33.99998,-9.49998 -34.99997,-31.49997c-0.99999,-21.99999 16.5,-41.99997 34.99997,-40.49997z");
    }
}


@keyframes layer2-main__animation {
    0% {
        d: path("m439.55475,141.46957c-11.23169,-22.36582 -44.85361,-46.91461 -79.14627,-66.03654c-34.29267,-19.12193 -74.0975,-35.74387 -118.09746,-26.74388c-43.99996,8.99999 -112.91455,86.35358 -82.91456,181.3535c29.99998,94.99993 129.35354,115.51211 178.3535,108.01211c48.99996,-7.5 77.6219,-49.30484 92.62187,-84.3048c14.99998,-34.99997 20.41461,-89.91456 9.18292,-112.28039z");
    }
    50% {
        d: path("m451.74987,140.25006c-15.49998,-36.99997 -53.99995,-33.49998 -94.99993,-57.49996c-40.99998,-23.99997 -67.99994,-45.49996 -111.9999,-36.49997c-43.99996,8.99999 -124.49991,95.49992 -94.49992,190.49984c29.99998,94.99993 138.49988,120.99991 187.49984,113.49991c48.99996,-7.5 82.49995,-61.49996 97.49992,-96.49992c14.99998,-34.99997 31.99997,-76.49993 16.49999,-113.4999z");
    }
    100% {
        d: path("m340.24996,175.25003c-6.99999,-37.99997 2,-67.49995 -14.49999,-102.99992c-16.49999,-35.49997 -63.49995,-36.99997 -96.99992,-25.99998c-33.49997,10.99999 -116.4999,79.99994 -72.49994,191.99984c43.99997,111.99991 148.49988,127.99989 197.49984,110.49991c48.99996,-17.49999 64.99995,-61.99995 57.49995,-87.99993c-7.49999,-25.99998 -53.49996,-29.49997 -70.99994,-85.49992z");
    }
}

@keyframes layer2-mini__animation {
    0% {
        d: path("m301.74998,142.25005c-29.49997,0 -56.49995,21.49998 -57.99995,55.99995c-1.5,34.49997 25.49998,61.49995 58.99995,62.99995c33.49997,1.5 58.49995,-28.99998 58.49995,-60.99995c0,-31.99997 -29.99997,-57.99995 -59.49995,-57.99995z");
    }
    50% {
        d: path("m301.74998,142.25005c-29.49997,0 -56.49995,21.49998 -57.99995,55.99995c-1.5,34.49997 25.49998,61.49995 58.99995,62.99995c33.49997,1.5 58.49995,-28.99998 58.49995,-60.99995c0,-31.99997 -29.99997,-57.99995 -59.49995,-57.99995z");
    }
    100% {
        d: path("m416.74989,98.25009c-29.49997,0 -56.49995,21.49998 -57.99995,55.99995c-1.5,34.49997 25.49998,61.49995 58.99995,62.99995c33.49997,1.5 58.49995,-28.99998 58.49995,-60.99995c0,-31.99997 -29.99997,-57.99995 -59.49995,-57.99995z");
    }
}

@keyframes layer3__animation {
    0% {
        d: path("m190.5062,251.21337c-18.52436,-42.76824 -10.2317,-93.84136 3.41461,-118.71939c13.64632,-24.87803 42.98778,-32.51219 69.98775,-39.51218c26.99998,-6.99999 41.79266,-13.15853 65.1219,-10.59755c23.32924,2.56098 25.98778,8.03656 45.48776,19.03656c19.49998,11 46.80484,28.48783 49.17068,43.21948c2.36583,14.73165 2.78049,17.81703 -0.57316,42.78043c-3.35365,24.96341 -15.35366,43.19511 -30.19509,63.63413c-14.84143,20.43902 -22.14632,46.79262 -73.45115,62.89017c-51.30484,16.09755 -110.43894,-19.96341 -128.9633,-62.73165z");
    }
    50% {
        d: path("m184.40864,257.31093c-29.49998,-63.49995 -7.79268,-130.42673 12.56095,-146.15842c20.35363,-15.73169 39.939,-6.90243 66.93897,-13.90242c26.99998,-6.99999 39.96338,-19.86583 65.1219,-19.13413c25.15851,0.73171 25.98778,12.30485 45.48776,23.30485c19.49998,11 54.73167,26.65856 65.63409,49.9268c10.90242,23.26824 13.7561,42.20727 -0.57316,56.80482c-14.32926,14.59755 -22.06097,11.48779 -40.56094,33.75608c-18.49997,22.26828 -31.90242,64.47555 -83.20725,80.5731c-51.30484,16.09755 -101.90235,-1.67073 -131.40232,-65.17068z");
    }
    100% {
        d: path("m180.7501,259.74995c-29.49998,-63.49995 -14.5,-122.49989 14.99998,-142.49988c29.49997,-19.99998 37.49997,-12.99999 64.49994,-19.99998c26.99998,-6.99999 48.49997,-34.49998 69.99995,-29.49998c21.49998,5 20.49998,24.49997 39.99996,35.49997c19.49998,11 58.99996,-1.99998 75.99994,41.99997c16.99999,43.99996 4,60.49995 -8.49999,68.99994c-12.49999,8.49999 -24.49999,5.99999 -42.99996,23.99998c-18.49998,17.99999 -37.99998,78.49994 -76.49994,88.49993c-38.49997,9.99999 -107.99991,-3.5 -137.49988,-66.99995z");
    }
}

@keyframes layer4__animation {
    0% {
        d: path("m229.44518,257.49385c-17.51218,-26.35363 -17.14633,-82.87797 19.79266,-110.97551c36.939,-28.09754 66.69506,-28.12192 99.19503,-19.12193c32.49998,8.99999 47.39018,37.68288 47.26824,60.97555c-0.12194,23.29266 -6.40241,41.64631 -27.90239,58.6463c-21.49998,16.99998 -40.30486,31.29265 -60.97557,37.19508c-20.67071,5.90243 -59.8658,-0.36586 -77.37797,-26.71949z");
    }
    50% {
        d: path("m218.46957,265.42068c-22.99998,-35.49997 -6.17072,-90.8048 30.76827,-118.90234c36.939,-28.09754 71.57311,-26.29265 104.07308,-17.29266c32.49998,8.99999 57.75603,36.46337 57.63409,59.75604c-0.12194,23.29266 -21.64631,41.03655 -43.14629,58.03654c-21.49998,16.99998 -37.25608,31.90241 -59.75606,43.9024c-22.49998,11.99999 -66.57311,9.99999 -89.57309,-25.49998z");
    }
    100% {
        d: path("m217.25006,267.24995c-22.99998,-35.49997 -7.99999,-102.99992 26.49998,-124.9999c34.49997,-21.99998 79.49993,-32.99997 111.9999,-23.99998c32.49998,8.99999 72.99994,44.99996 67.99995,74.99994c-5,29.99997 -37.49997,32.49997 -58.99995,49.49996c-21.49998,16.99998 -27.49998,37.99997 -49.99996,49.99996c-22.49998,11.99999 -74.49994,9.99999 -97.49992,-25.49998z");
    }
}
<div class="full-screen background"></div>
<div class="svg__container">
    <svg class="svg-container">
        
        <defs>
            <filter id="gooey-filter">
                <feGaussianBlur in="SourceGraphic" stdDeviation="20" result="blur" />
                <feColorMatrix in="blur" type="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
                <feComposite in="SourceGraphic" in2="goo" operator="atop" />
            </filter>

            <filter id="drop-shadow-filter">
                <feGaussianBlur in="SourceGraphic" stdDeviation="30" result="blur" />
            </filter>
        </defs>


        <rect class="full-screen" fill="#003459"></rect>


        <mask id="mask4">
            <rect class="mask__area" width="100%" height="100%" />
            <path class="layer4" transform="scale(4)" fill="black" d="m229.44518,257.49385c-17.51218,-26.35363 -17.14633,-82.87797 19.79266,-110.97551c36.939,-28.09754 66.69506,-28.12192 99.19503,-19.12193c32.49998,8.99999 47.39018,37.68288 47.26824,60.97555c-0.12194,23.29266 -6.40241,41.64631 -27.90239,58.6463c-21.49998,16.99998 -40.30486,31.29265 -60.97557,37.19508c-20.67071,5.90243 -59.8658,-0.36586 -77.37797,-26.71949z" />
        </mask>
        
        <g class="drop-shadow">
            <g class="full-screen gooey-filter">
                <rect fill="black" width="100%" height="100%" mask="url(#mask4)"></rect>
            </g>
        </g>

        <g class="full-screen gooey-filter">
            <rect fill="rgb(0, 96, 132)" style="transform: translate(18px, 18px);" width="100%" height="100%" mask=url(#mask4)></rect>
            <rect fill="rgb(0, 101, 142)" style="transform: translate(15px, 15px);" width="100%" height="100%" mask=url(#mask4)></rect>
            <rect fill="rgb(0, 106, 147)" style="transform: translate(12px, 12px);" width="100%" height="100%" mask=url(#mask4)></rect>
            <rect fill="rgb(0, 111, 152)" style="transform: translate(9px, 9px);" width="100%" height="100%" mask=url(#mask4)></rect>
            <rect fill="rgb(0, 116, 157)" style="transform: translate(6px, 6px);" width="100%" height="100%" mask=url(#mask4)></rect>
            <rect fill="rgb(0, 121, 162)" style="transform: translate(3px, 3px);" width="100%" height="100%" mask=url(#mask4)></rect>
            <rect fill="#007EA7" width="100%" height="100%" mask=url(#mask4)></rect>
        </g>


        <mask id="mask3">
            <rect class="mask__area" width="100%" height="100%" />
            <path class="layer3" transform="scale(4)" fill="black" d="m190.5062,251.21337c-18.52436,-42.76824 -10.2317,-93.84136 3.41461,-118.71939c13.64632,-24.87803 42.98778,-32.51219 69.98775,-39.51218c26.99998,-6.99999 41.79266,-13.15853 65.1219,-10.59755c23.32924,2.56098 25.98778,8.03656 45.48776,19.03656c19.49998,11 46.80484,28.48783 49.17068,43.21948c2.36583,14.73165 2.78049,17.81703 -0.57316,42.78043c-3.35365,24.96341 -15.35366,43.19511 -30.19509,63.63413c-14.84143,20.43902 -22.14632,46.79262 -73.45115,62.89017c-51.30484,16.09755 -110.43894,-19.96341 -128.9633,-62.73165z" />
        </mask>
        
        <g class="drop-shadow">
            <g class="full-screen gooey-filter">
                <rect fill="black" width="100%" height="100%" mask="url(#mask3)"></rect>
            </g>
        </g>

        <g class="full-screen gooey-filter">
            <rect fill="rgb(0,138,202)" style="transform: translate(18px, 18px);" width="100%" height="100%" mask=url(#mask3)></rect>
            <rect fill="rgb(0,143,207)" style="transform: translate(15px, 15px);" width="100%" height="100%" mask=url(#mask3)></rect>
            <rect fill="rgb(0,148,212)" style="transform: translate(12px, 12px);" width="100%" height="100%" mask=url(#mask3)></rect>
            <rect fill="rgb(0,153,217)" style="transform: translate(9px, 9px);" width="100%" height="100%" mask=url(#mask3)></rect>
            <rect fill="rgb(0,158,222)" style="transform: translate(6px, 6px);" width="100%" height="100%" mask=url(#mask3)></rect>
            <rect fill="rgb(0,163,227)" style="transform: translate(3px, 3px);" width="100%" height="100%" mask=url(#mask3)></rect>
            <rect fill="#00A8E8" width="100%" height="100%" mask=url(#mask3)></rect>
        </g>


        <mask id="mask2">
            <rect class="mask__area" width="100%" height="100%" />
            <path class="layer2-main" transform="scale(4)" fill="black" d="m439.55475,141.46957c-11.23169,-22.36582 -44.85361,-46.91461 -79.14627,-66.03654c-34.29267,-19.12193 -74.0975,-35.74387 -118.09746,-26.74388c-43.99996,8.99999 -112.91455,86.35358 -82.91456,181.3535c29.99998,94.99993 129.35354,115.51211 178.3535,108.01211c48.99996,-7.5 77.6219,-49.30484 92.62187,-84.3048c14.99998,-34.99997 20.41461,-89.91456 9.18292,-112.28039z" />
            <path class="layer2-small" transform="scale(4)" fill="black" d="m301.74998,142.25005c-29.49997,0 -56.49995,21.49998 -57.99995,55.99995c-1.5,34.49997 25.49998,61.49995 58.99995,62.99995c33.49997,1.5 58.49995,-28.99998 58.49995,-60.99995c0,-31.99997 -29.99997,-57.99995 -59.49995,-57.99995z" />
        </mask>

        <g class="drop-shadow">
            <g class="full-screen gooey-filter">
                <rect fill="black" width="100%" height="100%" mask="url(#mask2)"></rect>
            </g>
        </g>
        
        <g class="full-screen gooey-filter">
            <rect fill="rgb(217,217,219)" style="transform: translate(18px, 18px);" width="100%" height="100%" mask=url(#mask2)></rect>
            <rect fill="rgb(222,222,224)" style="transform: translate(15px, 15px);" width="100%" height="100%" mask=url(#mask2)></rect>
            <rect fill="rgb(227,227,229)" style="transform: translate(12px, 12px);" width="100%" height="100%" mask=url(#mask2)></rect>
            <rect fill="rgb(232,232,234)" style="transform: translate(9px, 9px);" width="100%" height="100%" mask=url(#mask2)></rect>
            <rect fill="rgb(237,237,239)" style="transform: translate(6px, 6px);" width="100%" height="100%" mask=url(#mask2)></rect>
            <rect fill="rgb(242,242,244)" style="transform: translate(3px, 3px);" width="100%" height="100%" mask=url(#mask2)></rect>
            <rect fill="#F7F7F9" width="100%" height="100%" mask=url(#mask2)></rect>
        </g>
        


        <mask id="mask1">
            <rect class="mask__area" width="100%" height="100%" />
            <path class="layer1-main" transform="scale(4)" fill="black" d="m144.81109,43.71449c27.41462,-22.10974 62.89021,-29.31703 106.8048,-28.65849c43.91459,0.65854 76.29263,18.13413 129.39015,35.84144c53.09752,17.70731 128.73155,28.86581 136.35349,95.4999c7.62194,66.63409 -4.98773,66.60971 -21.08527,114.13407c-16.09754,47.52437 -22.37806,57.25605 -49.74391,81.15847c-27.36584,23.90242 -108.36579,32.30483 -192.75592,18.56094c-84.39013,-13.74388 -155.2834,-68.88713 -167.102,-104.11269c-11.8186,-35.22556 -18.1033,-112.09064 1.46966,-148.47019c19.57297,-36.37954 29.25438,-41.84371 56.669,-63.95345z" />
            <path class="layer1-small" transform="scale(4)" fill="black" d="m152.67701,106.22571c18.49997,-3.37805 33.67071,11.99999 35.49998,34.99997c1.82927,22.99998 -17.2317,37.49997 -35.49998,36.99997c-18.26828,-0.5 -31.56096,-11.32925 -32.56095,-33.32924c-0.99999,-21.99999 14.06098,-35.29265 32.56095,-38.6707z" />
        </mask>

        <g class="drop-shadow">
            <g class="full-screen gooey-filter">
                <rect fill="black" width="100%" height="100%" mask="url(#mask1)"></rect>
            </g>
        </g>
        
        <g class="full-screen gooey-filter">
            <rect fill="rgb(225,225,225)" style="transform: translate(18px,18px);" width="100%" height="100%" mask=url(#mask1)></rect>
            <rect fill="rgb(230,230,230)" style="transform: translate(15px,15px);" width="100%" height="100%" mask=url(#mask1)></rect>
            <rect fill="rgb(235,235,235)" style="transform: translate(12px,12px);" width="100%" height="100%" mask=url(#mask1)></rect>
            <rect fill="rgb(240,240,240)" style="transform: translate(9px,9px);" width="100%" height="100%" mask=url(#mask1)></rect>
            <rect fill="rgb(245,245,245)" style="transform: translate(6px,6px);" width="100%" height="100%" mask=url(#mask1)></rect>
            <rect fill="rgb(250,250,250)" style="transform: translate(3px,3px);" width="100%" height="100%" mask=url(#mask1)></rect>
            <rect fill="white" width="100%" height="100%" mask=url(#mask1)></rect>
        </g>


        <!-- Border -->
        <rect stroke="white" stroke-width="20px" width="100%" height="100%" fill="rgba(0,0,0,0)"></rect>

    </svg>
</div>  
...