Pixi.js: Soporte real de SVG

Creado en 29 jun. 2017  ·  30Comentarios  ·  Fuente: pixijs/pixi.js

Sería genial para Pixi poder crear una representación de jerarquía gráfica de un SVG (no solo cargar una textura como la actual).

@psyrendust ^ Oye, ¿puedes hacer relaciones públicas con el que hiciste en Pixi? :D

Stale 🙏 Feature Request

Comentario más útil

Creo que esto hace lo que quieres usando webpack.
https://github.com/blunt1337/pixi-svg-loader

Todos 30 comentarios

Es posible que desee consultar esta biblioteca que hice:
https://github.com/bigtimebuddy/pixi-svg
https://bigtimebuddy.github.io/pixi-svg/example/

Debido a las limitaciones de dibujar en Pixi, no todas las funciones de svg son compatibles.

@trusktr, ¿ podrías dar un caso de uso? ¿Te refieres a tener grupos como Contenedores y conjuntos de primitivos como Sprites?

Porque esto es algo en lo que he estado pensando. Podría ser posible crear un atlas de texturas y usar las traducciones y rotaciones de SVG para crear una jerarquía de Sprites.

Un problema que veo con este enfoque son los anclajes (en caso de que queramos animar algo). Por ejemplo, Inkscape agrega anclajes como atributos personalizados, pero no están en el afaik estándar. Un ejemplo de lo que quiero decir:

2017-07-01 08_56_56-_new document 1 - inkscape

El ancla de ese grupo de tres caminos (arriba a la izquierda del rectángulo azul) se define como inkscape:transform-center-x y inkscape:transform-center-y .

    <g
       id="g4512"
       inkscape:transform-center-x="-65.892627"
       inkscape:transform-center-y="43.567609"
       transform="rotate(-5.9407468,27.740957,88.735118)">
      <path
         inkscape:connector-curvature="0"
         id="rect4485"
         d="m 24.502618,78.898505 h 50.619309 c 3.986749,0 7.196297,3.209548 7.196297,7.196296 v 70.274069 c 0,3.98675 -3.209548,7.1963 -7.196297,7.1963 H 24.502618 c -3.986748,0 -7.196296,-3.20955 -7.196296,-7.1963 V 86.094801 c 0,-3.986748 3.209548,-7.196296 7.196296,-7.196296 z"
         style="opacity:1;fill:#005e92;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke" />
      <path
         inkscape:connector-curvature="0"
         id="rect4485-4"
         d="m 66.160572,123.8869 h 50.619318 c 3.98675,0 7.1963,3.20955 7.1963,7.1963 v 70.27406 c 0,3.98675 -3.20955,7.19631 -7.1963,7.19631 H 66.160572 c -3.986734,0 -7.196284,-3.20956 -7.196284,-7.19631 V 131.0832 c 0,-3.98675 3.20955,-7.1963 7.196284,-7.1963 z"
         style="opacity:1;fill:#920000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke" />
      <path
         inkscape:connector-curvature="0"
         id="rect4485-3"
         d="m 106.60403,73.994048 h 50.61931 c 3.98675,0 7.1963,3.209548 7.1963,7.196296 v 70.274066 c 0,3.98675 -3.20955,7.19631 -7.1963,7.19631 h -50.61931 c -3.98675,0 -7.196288,-3.20956 -7.196288,-7.19631 V 81.190344 c 0,-3.986748 3.209538,-7.196296 7.196288,-7.196296 z"
         style="opacity:1;fill:#009228;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke" />
    </g>

Aunque aprecio tu esfuerzo @bigtimebuddy , no creo que sea una buena idea renderizar primitivas SVG en pixi.

Mira esto también:
https://css-tricks.com/rendering-svg-paths-in-webgl/

Creo que esto hace lo que quieres usando webpack.
https://github.com/blunt1337/pixi-svg-loader

@OSUblake genial, de hecho parece hacer lo que quise decir. Tengo que intentarlo. 👍

@bigtimebuddy ¡Gracias! Abrí un nuevo número allí. Sería genial tener un gráfico de escena Pixi completo.

@RanzQ

@trusktr, ¿ podrías dar un caso de uso? ¿Te refieres a tener grupos como Contenedores y conjuntos de primitivos como Sprites?

Sí, pero las primitivas serían Graphics objetos en lugar de sprites.

Un problema que veo con este enfoque son los anclajes (en caso de que queramos animar algo). Por ejemplo, Inkscape agrega anclajes como atributos personalizados, pero no están en el afaik estándar. Un ejemplo de lo que quiero decir:

No me importa no admitir cosas no estándar, puedo vivir solo con las API estandarizadas. Fácilmente podría haber un complemento para admitir cosas específicas de inkscape.

Aunque aprecio tu esfuerzo @bigtimebuddy , no creo que sea una buena idea renderizar primitivas SVG en pixi.

¿Por qué exactamente piensas eso?

@OSUblake

Creo que esto hace lo que quieres usando webpack.
https://github.com/blunt1337/pixi-svg-loader

Eso es bastante bueno, excepto que se limita a Webpack, y también se limita a entornos con herramientas, no se ejecuta en el cliente. Estoy buscando una API que pueda usar con Pixi.js en tiempo de ejecución (no en tiempo de compilación).


Lo que quiero (creo, pero no soy el usuario de Pixi.js más experto, así que avise si algo más es mejor como usar sprites) es tener un gráfico de escena DisplayObject que tenga la misma estructura que el DOM de SVG usado para generar el árbol Pixi de. Esto, para mí, es poderoso para la manipulación y la animación, sin tener que volver a renderizar todo el SVG en cada cuadro solo para animar una primitiva (posiblemente entre cientos o miles).

Lo que creo que voy a hacer, si no existe todavía algo de código abierto, es tomar @bigtimebuddy 's Pixi-SVG o @saschagehlich' s Pixi-SVG-gráficos , y modificarlos (o utilizar conceptos similares) para crear una Pixi Graphics árbol que refleja el árbol SVG en lugar de simplemente dibujar en un solo objeto Graphics .

@trusktr Ya veo, para animaciones basadas en primitivas podría ser útil crear objetos Graphics lugar de Sprites . Pero creo que la solución podría admitir Graphics para SVG simples y Sprites para los más complejos.

La razón por la que pensé que no era una buena idea es el hecho de que se han realizado muchos esfuerzos para crear renderizadores SVG personalizados y, en mi experiencia, siempre terminan teniendo este TODO de cosas no compatibles.

Eso será un problema para un artista, ya que es necesario saber qué funciones se pueden usar y cuáles no. Ya tenemos un buen renderizador SVG, el navegador. Pero si el SVG solo contiene primitivas simples sin efectos, entonces probablemente esté bien analizarlo como Graphics objetos.

Un ejemplo en el que los sprites funcionarían mejor , el mapa se ve muy nítido (tal vez solo falta el antialiasing) y funciona mal ya que las rutas son complejas.

Crear texturas a partir de un SVG es bastante fácil con canvas 2d y la api Path2D .

var path = new Path2D("M10 10 h 80 v 80 h -80 Z");
context.fill(path);

Demostración de Path Morphing
https://codepen.io/osublake/pen/oWzVvb

Iba a trabajar en un polyfill mejor ya que el de Google tiene problemas para analizar rutas SVG complejas.
https://github.com/google/canvas-5-polyfill

@RanzQ

Ya tenemos un buen renderizador SVG, el navegador.

Pero es tan lento. ¿Se renderiza en la GPU o en la CPU? Para mí, el rendimiento que experimento no se compara con la velocidad de cosas similares dibujadas con Pixi.js, por ejemplo. Me parece que el motor SVG nativo está haciendo demasiado trabajo.

Incluso Canvas 2d es lento en comparación con WebGL. Compare aquí la diferencia entre WebGL y Canvas: http://pixijs.github.io/pixi-particles-editor/ (desplácese hasta la parte inferior para alternar entre la representación de WebGL y Canvas). Canvas es notablemente más lento.

Solo quiero dibujar SVG y que sea lo más rápido posible. Hasta ahora, conceptualmente al menos, parece que dibujar SVG con una API WebGL como Pixi.js o Two.js es la forma más rápida de hacerlo. El único inconveniente en este momento es que no todas las funciones de SVG son completamente compatibles.

@OSUblake

Crear texturas a partir de un SVG es bastante fácil con canvas 2d y la api Path2D.

Canvas 2D sigue siendo notablemente más lento que WebGL, mira esa demostración que acabo de vincular dos párrafos.

Demostración de Path Morphing
https://codepen.io/osublake/pen/oWzVvb

¡Genial demo! En este caso, está animando una ruta simple en PathProxy. Probablemente, esto sea lo suficientemente rápido para el caso de uso. Pero imagina dibujar un montón de cosas en un SVG, como 100 nodos, y animarlas todas, y luego querer que todo eso sea una textura para envolver una esfera.

O imagine que las partículas en esa demostración se hacen con SVG y animan los nodos DOM de SVG, luego toman el renderizado como una textura con drawImage en un lienzo y finalmente lo colocan en un quad de una aplicación webgl 3D. ¡Sería demasiado lento!

Su demostración es rápida porque esa animación de partículas está en WebGL a través de Pixi.

Si la renderización de SVG con Pixi fuera una función compatible y se creara una jerarquía que reflejara la jerarquía de SVG, entonces sería posible mapear los cambios a un elemento display:none <svg> ( display:none para que, con suerte, evite que el motor SVG del navegador funcione porque no es necesario procesar nada) en cambios en un árbol Pixi.js.

Creo que esta sería la forma más rápida de dibujar SVG porque Pixi es más rápido, al tiempo que ofrece la conveniencia de un DOM que puede ser manipulado por React, Angular, etc. Quiero tener un árbol SVG DOM que pueda manipular, quién lo hará ser más rápido que el lento motor SVG del navegador. Quizás estoy pidiendo demasiado. Parece que con la tecnología actual, la renderización SVG es demasiado lenta según los estándares comunes (queremos velocidades del motor de juegos).

@trusktr

Pero es tan lento.

Con eso quise decir que podemos dibujar texturas SVG usando el navegador, es lento pero admite todas las funciones. Por supuesto, no harías animaciones como esa. Podrías crear un atlas de texturas y animar los sprites después. Si desea crear personajes espinales en 2D, por ejemplo, ese sería el camino a seguir.

Creo que este es un ejemplo de lo que buscas: https://github.com/bodymovin/bodymovin/issues/184

La tarea no es simple y esa animación, por ejemplo, es lo suficientemente compleja como para reproducirse lentamente en mi antiguo teléfono Android, que reproduce bien escenas de Pixi basadas en sprites. No veo ninguna diferencia en la versión SVG y Pixi. Sin embargo, podría ser solo un problema de optimización.

Consulte esto también: https://www.gatherdigital.co.uk/community/post/high-performance-webgl/78

Entonces, en mi opinión, hay dos tipos diferentes de necesidades para SVG. Uno con menos características SVG, dividido en primitivas, el otro con atlas renderizado por navegador, siendo los sprites los nodos <g> por ejemplo.

Otro enfoque podría ser encontrar un mejor formato o herramientas interoperables para gráficos vectoriales que SVG. Si quieres algo escalable, SVG tiene sus limitaciones en PixiJS por razones que @RanzQ ya expresó. Hay tantas funciones no compatibles con las capacidades de dibujo de Pixi disponibles en SVG que cualquier traducción de dibujo primitiva será de segunda categoría.

Otro enfoque que recomendaría es PixiAnimate (https://github.com/jiborobot/pixi-animate-extension) que es una extensión nativa (descargo de responsabilidad, yo soy el autor de esto) para Adobe Animate que hace un buen trabajo exportando gráficos precisos. Además, puede crear la jerarquía que desee utilizando símbolos y capas anidados o animar.

@bigtimebuddy ¿Existe un flujo de trabajo para crear atlas de texturas a partir de gráficos vectoriales utilizando Animate? He estado buscando un flujo de trabajo en el que la escena Pixi pueda crearse con la ayuda de la interfaz de usuario.

Parece que es posible crear atlas en la nueva versión de Animate, pero ¿ha probado su extensión para esto ?: http://blogs.adobe.com/contentcorner/2017/07/03/create-a-texture-atlas-with -animate-cc-para-tus-motores-de-juegos-favoritos /

@RanzQ , sí, PixiAnimate puede exportar imágenes u hojas de sprites separadas en el formato de atlas de TexturePackers. Sin embargo, las formas vectoriales no se convierten automáticamente en texturas. Necesita usar "Convertir a mapa de bits" para hacer eso en Animate.

@trusktr

Su demostración es rápida porque esa animación de partículas está en WebGL a través de Pixi.

Exactamente. No estaba sugiriendo usar lienzo como el renderizador principal. Solo para generar texturas / sprites cuando cambia la geometría. Debería ser lo suficientemente rápido para la mayoría de los casos de uso. Creo que así es como Two.js representa la ruta en WebGL.

Y el uso de objetos Path2D puede mejorar el rendimiento del lienzo, ya que el navegador almacenará en caché los vectores de una ruta. Esto le permite utilizar el mismo objeto de ruta más de una vez, incluso con diferentes contextos y resoluciones de lienzo.

@OSUblake

Exactamente. No estaba sugiriendo usar lienzo como el renderizador principal. Solo para generar texturas / sprites cuando cambia la geometría. Debería ser lo suficientemente rápido para la mayoría de los casos de uso. Creo que así es como Two.js representa la ruta en WebGL.

Sí, esto parece un buen enfoque. Por ejemplo, si los únicos atributos que se modifican en un elemento <circle> son cx y cy , esto significa que una optimización sería traducir una malla o sprite existente sin crear uno nuevo.

Aquí hay una comparación entre Pixi, Two y SVG nativo:

¿Por qué Pixi es notablemente más lento? ¿Es porque recalcula (vuelve a tessalates o re-rasteriza) en función de los comandos de dibujo de cada fotograma?

Con Two.js, un círculo es un objeto con propiedades x, y y radio. Es obvio con esa API que el círculo no necesita ser reevaluado / rerasterizado si se modifica solo xey.

No es tan obvio cómo se haría esta optimización con el estilo de comando de dibujo de Pixi.

@trusktr

¿Por qué Pixi es notablemente más lento? ¿Es porque recalcula (vuelve a tessalates o re-rasteriza) en función de los comandos de dibujo de cada fotograma?

No. Es solo crear muchos triángulos, lo que está acabando con el rendimiento de la GPU. Puede ver la diferencia si dibuja un rectángulo sin un estilo de línea. Lo renderizará como un sprite, por lo que el rendimiento será mucho mejor. 10,000 rectos.
https://codepen.io/osublake/pen/PjrbWq/

¿Ha pensado en utilizar campos de distancia para la rasterización? Sé que funciona bien con fuentes si no te acercas demasiado. Me pregunto si podría usarse para animar los datos de la ruta.
https://github.com/Tw1ddle/WebGL-Distance-Fields/tree/master/sdf

https://www.shadertoy.com/view/ltXSDB

Mis ejemplos anteriores eran completamente inexactos porque no me di cuenta de que JSBin estaba saliendo de los bucles for antes, por lo que en mi Macbook Pro solo mostraba 500 círculos (incluso si configuré n en 10000 ). Actualicé los ejemplos, por lo que todos representan 2000 círculos sin romper el bucle de JSBin:

El ejemplo de SVG sigue siendo más lento cuando se animan solo las posiciones del círculo (no el radio).

Aquí están Two.js y SVG que también animan radios:

No incluí la versión de Pixi.js porque no estaba seguro de cómo modificar la versión de animación sin radio. ¿Cómo actualizaría la versión sin animación de radio usando Pixi.js para incluir la animación de radio?

¿Cómo actualizaría la versión sin animación de radio usando Pixi.js para incluir la animación de radio?

El rendimiento realmente puede comenzar a caer en picada aquí. Tienes que borrar el objeto gráfico, que reinicia todo.
https://codepen.io/osublake/pen/8217810e590672c5a5327596e33c4b1a?editors=0010

Ahora mire esta demostración usando Canvas 2d para generar las texturas. 3000 círculos corriendo a 60 fps sólidos en mi máquina.
https://codepen.io/osublake/full/MoMeMg/

Bueno, de todos modos, creo que hay un buen caso de uso para esto, como muestra el ejemplo: puede ser mucho más rápido en WebGL en algunos casos.

@OSUblake Ups, respondí esa última antes de ver tu nueva respuesta.

El rendimiento realmente puede comenzar a caer en picada aquí. Tienes que borrar el objeto gráfico, que reinicia todo.
https://codepen.io/osublake/pen/8217810e590672c5a5327596e33c4b1a?editors=0010

Eso es lo que temía, que no es lo ideal. Comienza a acercarse a la lentitud del SVG nativo.

Ahora mire esta demostración usando Canvas 2d para generar las texturas. 3000 círculos corriendo a 60 fps sólidos en mi máquina.
https://codepen.io/osublake/full/MoMeMg/

¡Mierda, guau! ¡Okey! Entonces, ahí vamos, ¡esa es actualmente la mejor manera de hacerlo (y con 3000 <canvas> incluso)!

¿Por qué es mucho más rápido? ¿Quizás los implementadores nativos de SVG puedan aprender de esto (así como Pixi.js y Two.js)?

¿Quizás usar este enfoque en Pixi.js requeriría cambios en la colisión / selección? Habría una textura rectangular en lugar de una malla.

@trusktr La razón por la que es rápido es que dibuja en el lienzo una vez y luego lo carga como una textura en la GPU. En ese ejemplo, hay una textura separada generada para cada radio redondeado a pasos de 4px (si lo entendí correctamente 😄). La animación es lo suficientemente rápida para que no vea el cambio de textura.

Puede hacer cosas similares con la API de dibujo de Pixi almacenando en caché los objetos gráficos ( cacheAsBitmap ). De esa manera, puede dibujar sus primitivas una vez y volver a dibujarlas rápidamente desde la caché.

En ese ejemplo, hay una textura separada generada para cada radio redondeado a pasos de 4px (si lo entendí correctamente 😄)

En realidad, se redondea a incrementos de 0,25. ¿Cuánta precisión de subpíxeles puede ver realmente?

Si te parece gracioso, mira cómo funciona el CanvasTinter de Pixi. O cómo funcionan las animaciones de la hoja de sprites. Sacrifica algo de memoria a cambio de rendimiento, y con una buena estrategia de almacenamiento en caché puede funcionar.

Puede hacer cosas similares con la API de dibujo de Pixi almacenando en caché los objetos gráficos (cacheAsBitmap). De esa manera, puede dibujar sus primitivas una vez y volver a dibujarlas rápidamente desde la caché.

Es posible que el uso de cacheAsBitmap no se vea bien porque los gráficos tendrán alias. Para obtener gráficos con suavizado, debe usar generateCanvasTexture. Entonces, de cualquier manera, terminas con un lienzo, pero usando la API de gráficos de Pixi no puedes hacer cosas simples, como cambiar el trazo de línea del trazo.

Puede hacer cosas similares con la API de dibujo de Pixi almacenando en caché los objetos gráficos (cacheAsBitmap).

Para obtener gráficos con suavizado, debe usar generateCanvasTexture

Con cualquiera de esas dos opciones, ¿puedo animar el radio como en tu ejemplo @OSUblake ?

(por cierto, gracias chicos, abriendo mis ojos a técnicas de renderizado que no había imaginado antes).

@trusktr Sí, solo tienes que crear muchos objetos gráficos con diferentes radios y crear un mapa de las texturas generadas (para que luego puedas usar una textura en caché para cada radio). Con cacheAsBitmap mapearías los objetos Graphics en lugar de texturas pero no @OSUblake .

Este tipo de animación es una animación de hoja de sprites. Cuando puede animar usando transformaciones, entonces no es necesario el almacenamiento en caché de texturas. Como si no le importara que el trazo de los círculos también se escala, una simple animación de escala lo haría.

Pero estoy de acuerdo, Canvas tiene una mejor API de dibujo, así que la usaría. Y para SVG, la jerarquía se puede dividir en un atlas, como lo hace pixi-svg-loader (¿creo?). O si desea una hoja de sprites como una animación, eso también es posible dibujando los estados de la animación en el lienzo.

¿Quizás usar este enfoque en Pixi.js requeriría cambios en la colisión / selección? Habría una textura rectangular en lugar de una malla.

Aunque no es tan rápido como un polígono, el lienzo tiene un método para realizar pruebas de posicionamiento en una ruta,
https://codepen.io/osublake/pen/dzYzab/?editors=0010

Parece haber un svgloader en three.js, quizás algo que se pueda asignar a pixi.js
https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/SVGLoader.js

Este problema se ha marcado automáticamente como obsoleto porque no ha tenido actividad reciente. Se cerrará si no se produce más actividad. Gracias por sus aportaciones.

Este hilo se ha bloqueado automáticamente ya que no ha habido ninguna actividad reciente después de que se cerró. Abra un nuevo problema para errores relacionados.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

gaccob picture gaccob  ·  3Comentarios

readygosports picture readygosports  ·  3Comentarios

gigamesh picture gigamesh  ·  3Comentarios

Makio64 picture Makio64  ·  3Comentarios

madroneropaulo picture madroneropaulo  ·  3Comentarios