html5 - Optimización de hojas de sprites basadas en SVG para la aceleración de la GPU HW de CSS3 en el navegador(móvil)
webkit mobile-safari (2)
Durante la última semana he estado ayudando a un amigo a experimentar con hojas de sprites basadas en SVG en el navegador. Queríamos crear un flujo de trabajo ideal para preparar, publicar y ejecutar gráficos animados de alta calidad en el navegador. Por lo tanto, idealmente, tenga una única fuente de datos de animación que funcione para pantallas pequeñas de teléfonos inteligentes, tabletas, pantallas Retina y navegadores de escritorio.
En teoría, SVG (basado en vectores) debería ser ideal para eso, pero como SVG no suele usarse tanto, decidimos probarlo. La idea no era usar SMIL SVG (así que no hay animación basada en SVG) sino crear una hoja de sprites de animación (como lo haría normalmente con datos ráster PNG / JPG) pero hacer esto con vectores puros, es decir, SVG. Era un poco más grande, pero si funciona así, funcionaría incluso con algo aún más optimizado.
Además, la animación vectorial fotograma a fotograma podría hacer grandes cosas para nuestro flujo de trabajo: nos permitiría usar el editor de Flash para hacer las animaciones y luego exportarlas a hojas de sprite SVG.
De todos modos, el resultado funciona sorprendentemente bien pero también falla en algunas áreas (tenga en cuenta que para fines de prueba solo trabajamos con navegadores basados en Webkit, es decir, Safari, Chrome, Safari móvil en iOS y Android ICS).
En CSS, es bastante fácil activar la aceleración de hardware para una hoja de sprites como esta (al menos en los navegadores modernos con fotogramas clave y pasos); simplemente haz esto:
background-image: url(my.svg);
-webkit-animation: walk 1s steps(12, end) infinite;
para llamar a la animación basada en fotogramas clave que se muestra aquí:
@-webkit-keyframes walk {
from { -webkit-transform: translate3d(0, 0, 0); }
to { -webkit-transform: translate3d(-100%, 0, 0); }
}
donde el uso de translate3d debería permitir que la GPU se active y todo el hardware debería acelerarse en el navegador iOS móvil Safari y Android ICS.
Sorprendentemente, considerando que es una especie de técnica de fuerza bruta y una animación vectorial bastante grande (600x600px para la prueba), todo vuela. Pero no es perfecto: parpadea en Safari antes de despegar. Y en el navegador ICS parpadea todo el tiempo, por lo que no es realmente utilizable.
Así que probamos los trucos habituales para eliminar el parpadeo, como por ejemplo:
-webkit-transform: translateZ(0);
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
Pero eso no funcionó. Entonces intentamos rasterizar SVG dinámicamente en la memoria y usarlo como una textura con -webkit-transform: scale3d (1, 1, 0) pero eso no ayudó a ether.
Finalmente, simplemente reemplazamos el SVG con una hoja de sprite render PNG / JPG del mismo tamaño, pensando que los vectores complejos son demasiado para el navegador, pero ¿adivinen qué? Es el mismo problema, por lo que no es una representación SVG, es un problema de dibujo del navegador. Una prueba más de eso es si disminuimos la animación a 1FPS, el parpadeo aún persiste.
¿La imagen es demasiado grande para GPU? ¿Hemos alcanzado el límite de rendimiento de lo que puede dibujar / animar cómodamente en el navegador (en particular, el móvil)?
Realmente apreciaría ideas / hacks sobre cómo potencialmente deshacerse del parpadeo (especialmente desde que se realiza tan rápido). Es solo una técnica prometedora: animación de navegador de alto rendimiento que se adapta a diferentes tamaños de pantalla: HTML5 Holy Grail ;)
Con algunas optimizaciones como
<svg preserveAspectRatio="xMinYMax slice" viewBox="0 0 600 50">
y algo de magia CSS, podemos hacer que el SVG se adapte perfectamente a su contenedor y cambie su tamaño desde una única clase de CSS. Realmente funcionaría de maravilla, pero por desgracia el parpadeo.
De todos modos, lea más sobre esto aquí donde también puede probarlo .
No tengo ICS aquí para verificarlo, pero en iOS 6 en un iPhone 5 y Jelly Bean 4.1.1 en un Galaxy Nexus, la animación se ve bastante suave, excepto cuando hago zoom, en ese momento obtengo algunos fotogramas parpadeantes y luego se establece de nuevo.
Lo cual me recordó un problema similar que estaba teniendo la representación en un lienzo grande y su transformación en la pantalla (con la mayoría del lienzo fuera de la pantalla en un momento dado).
Mi análisis de caja negra en el momento sugería que era una optimización donde el navegador no se molestaba en mostrar contenido fuera de pantalla, en lugar de esperar hasta que se volviera visible, lo que derrotaba por completo el objetivo de tener la imagen grande y el hardware acelerándolo.
Mi "solución" fue -webkit-transform: escalar toda la imagen lo suficientemente pequeña como para garantizar que todo encaja en la pantalla (para que el navegador no tenga más remedio que renderizar la imagen completa), dejarla renderizar, y luego escalarla hasta la el tamaño que quería.
(Como nota aparte: para ocultar esta piratería del usuario, al principio experimenté con la configuración de opacidad: 0 para que el pre-render no fuera visible, pero parece que esto tuvo el mismo efecto que el procesamiento fuera de pantalla: se optimizó. Al final fijé la opacidad muy baja y la cubrí con un mensaje de "carga" casi opaco, lo que significa que el renderizado de fondo no era visible a simple vista, pero el navegador no tenía absolutamente visibles / invisibles para optimizar. No estoy seguro de si esto fue exagerado, pero pareció funcionar para mi configuración.)
Me interesaría saber si una técnica similar podría funcionar para usted.
Una idea genial
¿Qué hay de cambiar el zindex de los marcos para que esté superponiendo las imágenes una encima de la otra? Esto podría resolver el parpadeo porque durante el rediseño el último fotograma aún es visible. Entonces, seguirías aumentando el valor de zindex del último fotograma. Por supuesto, hay un límite y tendrá que restablecer el zindex de nuevo, pero podría tener un gran impacto en reducir el parpadeo.