Pixi.js: Suporte SVG real

Criado em 29 jun. 2017  ·  30Comentários  ·  Fonte: pixijs/pixi.js

Seria ótimo para Pixi ser capaz de criar uma representação de hierarquia gráfica de um SVG (não apenas carregar uma textura como atualmente).

@psyrendust ^ Ei, você pode fazer publicidade daquele que transformou no Pixi? : D

Stale 🙏 Feature Request

Comentários muito úteis

Eu acho que isso faz o que você deseja usando o webpack.
https://github.com/blunt1337/pixi-svg-loader

Todos 30 comentários

Você pode querer verificar esta biblioteca que fiz:
https://github.com/bigtimebuddy/pixi-svg
https://bigtimebuddy.github.io/pixi-svg/example/

Por causa das limitações de desenho no Pixi, nem todos os recursos svg são suportados.

@trusktr você poderia dar um caso de uso? Você quer dizer ter grupos como Containers e conjuntos de primitivas como Sprites?

Porque isso é algo em que estive pensando. Pode ser possível criar um atlas de textura e usar a tradução e rotação de SVG para criar uma hierarquia de Sprites.

Um problema que vejo com essa abordagem são as âncoras (no caso de querermos animar algo). Por exemplo, o Inkscape adiciona âncoras como atributos personalizados, mas eles não estão no afaik padrão. Um exemplo do que quero dizer:

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

A âncora desse grupo de três caminhos (canto superior esquerdo do retângulo azul) é definida como inkscape:transform-center-x e 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>

Embora eu aprecie seu esforço @bigtimebuddy , não acho uma boa ideia renderizar primitivos SVG em pixi.

Verifique isso também:
https://css-tricks.com/rendering-svg-paths-in-webgl/

Eu acho que isso faz o que você deseja usando o webpack.
https://github.com/blunt1337/pixi-svg-loader

@OSUblake legal, realmente parece fazer o que eu quis dizer. Tenho que tentar. 👍

@bigtimebuddy Obrigado! Eu abri uma nova edição ali. Seria ótimo ter um gráfico de cena Pixi completo.

@RanzQ

@trusktr você poderia dar um caso de uso? Você quer dizer ter grupos como Containers e conjuntos de primitivas como Sprites?

Sim, mas os primitivos seriam Graphics objetos em vez de sprites.

Um problema que vejo com essa abordagem são as âncoras (no caso de querermos animar algo). Por exemplo, o Inkscape adiciona âncoras como atributos personalizados, mas eles não estão no afaik padrão. Um exemplo do que quero dizer:

Não me importo em não suportar coisas não padronizadas, posso viver apenas com as APIs padronizadas. Poderia facilmente haver um plugin para suportar coisas específicas do inkscape.

Embora eu aprecie seu esforço @bigtimebuddy , não acho uma boa ideia renderizar primitivos SVG em pixi.

Por que exatamente você acha isso?

@OSUblake

Eu acho que isso faz o que você deseja usando o webpack.
https://github.com/blunt1337/pixi-svg-loader

Isso é muito legal, exceto se limitado ao Webpack, e também limitado a ambientes com ferramentas, não roda no cliente. Estou procurando uma API que posso usar com Pixi.js em tempo de execução (não em tempo de compilação).


O que eu quero (eu acho, mas não sou o usuário mais experiente do Pixi.js, então avise se algo mais é melhor como usar sprites) é ter um gráfico de cena DisplayObject que seja a mesma estrutura que o DOM SVG usado para gerar a árvore Pixi de. Isso, para mim, é poderoso para manipulação e animação, sem ter que renderizar novamente todo o SVG em cada quadro apenas para animar um primitivo (possivelmente entre centenas ou milhares).

O que eu acho que vai fazer, se algo open source ainda não existe, é tomar @bigtimebuddy 's Pixi-SVG ou @saschagehlich' s Pixi-svg-gráficos , e modificá-los (ou usar conceitos semelhantes) para criar um Pixi Graphics tree espelhando a árvore SVG ao invés de apenas desenhar em um único objeto Graphics .

@trusktr , vejo que, para animações baseadas em primitivas, pode ser útil criar objetos Graphics vez de Sprites . Mas acho que a solução poderia suportar ambos, Graphics para SVGs simples e Sprites para os mais complexos.

A razão pela qual achei que não era uma boa ideia é o fato de que houve muitos esforços para criar renderizadores SVG personalizados e, na minha experiência, eles sempre acabam tendo esse TODO de coisas sem suporte.

Isso será um problema para um artista, pois é preciso saber quais recursos podem ser usados ​​e quais não. Já temos um bom renderizador SVG, o navegador. Mas se o SVG contém apenas primitivos simples sem efeitos, provavelmente não há problema em analisá-lo como objetos Graphics .

Um exemplo onde sprites funcionariam melhor , o mapa parece muito crocante (talvez apenas sem o anti-serrilhamento) e tem um desempenho ruim, pois os caminhos são complexos.

Criar texturas a partir de um SVG é muito fácil usando canvas 2d e a API Path2D .

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

Demonstração de metamorfose de caminho
https://codepen.io/osublake/pen/oWzVvb

Eu estava trabalhando em um polyfill melhor, pois o do Google tem problemas para analisar caminhos SVG complexos.
https://github.com/google/canvas-5-polyfill

@RanzQ

Já temos um bom renderizador SVG, o navegador.

Mas é tão slooooooooow. Ele é renderizado na GPU ou na CPU? Para mim, o desempenho que experimento não se compara à velocidade de coisas semelhantes desenhadas com Pixi.js, por exemplo. Parece-me que o motor SVG nativo está trabalhando muito.

Mesmo o canvas 2d é lento em comparação com WebGL. Compare aqui a diferença entre WebGL e Canvas: http://pixijs.github.io/pixi-particles-editor/ (role até a parte inferior para alternar entre WebGL e renderização de Canvas). O Canvas é notavelmente mais lento.

Eu só quero desenhar SVG e que seja o mais rápido possível. Até agora, pelo menos conceitualmente, parece que desenhar SVGs com uma API WebGL como Pixi.js ou Two.js é o caminho mais rápido. A única desvantagem no momento é que nem todos os recursos SVG são totalmente suportados.

@OSUblake

Criar texturas a partir de um SVG é muito fácil usando canvas 2d e a API Path2D.

O Canvas 2D ainda é visivelmente mais lento do que o WebGL, veja aquela demonstração que acabei de vincular dois parágrafos.

Demonstração de metamorfose de caminho
https://codepen.io/osublake/pen/oWzVvb

Demonstração legal! Nesse caso, você está animando um caminho simples no PathProxy. Provavelmente, isso é rápido o suficiente para o caso de uso. Mas imagine desenhar um monte de coisas em um SVG, como 100 nós, e animar todos eles, e então querer que tudo isso como uma textura envolva uma esfera.

Ou imagine as partículas nessa demonstração sendo feitas com SVG e animando os nós do DOM SVG, em seguida, tomando a renderização como uma textura com drawImage em uma tela e, finalmente, colocando-a em um quad de um aplicativo webgl 3D. Seria muito lento!

Sua demonstração é rápida porque a animação de partículas está em WebGL via Pixi.

Se a renderização de SVGs com Pixi fosse um recurso compatível e uma hierarquia que espelhasse a hierarquia SVG fosse criada, seria possível mapear as alterações para um elemento display:none <svg> ( display:none para que isso evite que o mecanismo SVG do navegador funcione porque nada precisa ser renderizado) em alterações em uma árvore Pixi.js.

Eu acho que esta seria a maneira mais rápida de desenhar SVGs porque Pixi é mais rápido, enquanto oferece a conveniência de um DOM que pode ser manipulado por React, Angular, etc. Eu quero ter uma árvore SVG DOM que eu possa manipular, quem renderizará ser mais rápido do que o mecanismo SVG lento do navegador. Talvez eu esteja pedindo demais. Parece que com a tecnologia de hoje, a renderização de SVG é muito lenta para os padrões comuns (queremos velocidades do motor de jogos).

@trusktr

Mas é tão slooooooooow.

Com isso eu quis dizer que podemos desenhar texturas SVG usando o navegador, é lento, mas oferece suporte a todos os recursos. Você não faria animações como essa, é claro. Você pode criar um atlas de textura e animar os sprites depois. Se você gostaria de criar personagens espinhais 2D, por exemplo, esse seria o caminho a percorrer.

Acho que este é um exemplo do que você procura :

A tarefa não é simples e essa animação, por exemplo, é complexa o suficiente para ser reproduzida lentamente no meu antigo telefone Android, que reproduz perfeitamente cenas Pixi baseadas em sprites. Não vejo nenhuma diferença na versão SVG e Pixi. Pode ser apenas um problema de otimização.

Verifique também: https://www.gatherdigital.co.uk/community/post/high-performance-webgl/78

Portanto, em minha opinião, existem dois tipos diferentes de necessidades para o SVG. Um com menos recursos SVG, dividido em primitivos, o outro com atlas renderizado pelo navegador, sprites sendo os nós <g> , por exemplo.

Outra abordagem pode ser encontrar um formato ou ferramenta de interoperabilidade melhor para gráficos vetoriais do que o SVG. Se você deseja algo escalável, o SVG tem suas limitações no PixiJS por motivos que @RanzQ já articulou. Existem tantos recursos sem suporte nos recursos de desenho do Pixi disponíveis no SVG que qualquer tradução de desenho original será de segunda categoria.

Outra abordagem que eu recomendo é PixiAnimate (https://github.com/jiborobot/pixi-animate-extension) é uma extensão nativa (isenção de responsabilidade, eu fui o autor desta) para Adobe Animate que faz um bom trabalho exportando gráficos precisos. Além disso, você pode criar qualquer hierarquia que desejar usando símbolos e camadas aninhadas ou animar.

@bigtimebuddy Existe um fluxo de trabalho para criar atlas de textura a partir de gráficos vetoriais usando o Animate? Tenho procurado por um fluxo de trabalho onde a cena Pixi possa ser criada com a ajuda da IU.

Parece ser possível criar atlas na nova versão do Animate, mas você já tentou sua extensão para isso: http://blogs.adobe.com/contentcorner/2017/07/03/create-a-texture-atlas-with -animado-cc-para-seus-motores-de-jogo-favoritos /

@RanzQ , sim PixiAnimate pode exportar imagens separadas ou spritesheets no formato de atlas TexturePackers. As formas vetoriais, no entanto, não são convertidas automaticamente em texturas. Você precisa usar "Converter em bitmap" para fazer isso no Animate.

@trusktr

Sua demonstração é rápida porque a animação de partículas está em WebGL via Pixi.

Exatamente. Eu não estava sugerindo usar canvas como renderizador principal. Apenas para gerar texturas / sprites quando a geometria muda. Deve ser rápido o suficiente para a maioria dos casos de uso. Acho que é assim que Two.js faz renderização de caminhos em WebGL.

E usar objetos Path2D pode melhorar o desempenho da tela, pois o navegador armazenará em cache os vetores para um caminho. Isso permite que você use o mesmo objeto de caminho mais de uma vez, mesmo com diferentes contextos e resoluções de tela.

@OSUblake

Exatamente. Eu não estava sugerindo usar canvas como renderizador principal. Apenas para gerar texturas / sprites quando a geometria muda. Deve ser rápido o suficiente para a maioria dos casos de uso. Acho que é assim que Two.js faz renderização de caminhos em WebGL.

Sim, parece uma boa abordagem. Por exemplo, se os únicos atributos sendo modificados em um elemento <circle> são cx e cy , isso significa que uma otimização seria traduzir uma malha ou sprite existente sem criar um novo.

Aqui está uma comparação entre Pixi, Two e SVG nativo:

Por que Pixi está visivelmente mais lento? É porque ele recalcula (restaura ou rasteriza) com base nos comandos de desenho a cada quadro?

Com Two.js, um Circle é um objeto com propriedades x, y e radius. É óbvio com essa API que o círculo não precisa ser retessado / rerasterizado se for modificado apenas x e y.

Não é tão óbvio como essa otimização seria feita com o estilo de comando de desenho do Pixi.

@trusktr

Por que Pixi está visivelmente mais lento? É porque ele recalcula (restaura ou rasteriza) com base nos comandos de desenho a cada quadro?

Não. É apenas criar muitos triângulos, o que está matando o desempenho da GPU. Você pode ver a diferença se desenhar um retângulo sem um estilo de linha. Ele irá renderizá-lo como um sprite, então o desempenho será muito melhor. 10.000 retos.
https://codepen.io/osublake/pen/PjrbWq/

Você já examinou o uso de campos de distância para rasterização? Eu sei que funciona bem com fontes se você não aumentar muito o zoom. Estou me perguntando se ele poderia ser usado para animar dados de caminho.
https://github.com/Tw1ddle/WebGL-Distance-Fields/tree/master/sdf

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

Meus exemplos anteriores eram completamente imprecisos porque eu não percebi que JSBin estava saindo dos loops for antes, então no meu Macbook Pro ele estava renderizando apenas 500 círculos (mesmo se eu definir n como 10000 ). Eu atualizei os exemplos, então todos eles renderizam 2.000 círculos sem a quebra de loop de JSBin:

O exemplo SVG ainda é mais lento ao animar apenas as posições do círculo (não do raio).

Aqui estão Two.js e SVG também animando raios:

Não incluí a versão Pixi.js porque não tinha certeza de como modificar a versão sem animação radius. Como você atualizaria a versão sem animação de raio usando Pixi.js para incluir a animação de raio?

Como você atualizaria a versão sem animação de raio usando Pixi.js para incluir a animação de raio?

O desempenho pode realmente começar a despencar aqui. Você tem que limpar o objeto gráfico, o que redefine tudo.
https://codepen.io/osublake/pen/8217810e590672c5a5327596e33c4b1a?editors=0010

Agora veja esta demonstração usando canvas 2d para gerar as texturas. 3.000 círculos rodando a sólidos 60fps na minha máquina.
https://codepen.io/osublake/full/MoMeMg/

Bem, de qualquer forma, acho que há um bom caso de uso para isso, como mostra o exemplo: pode ser muito mais rápido no WebGL em alguns casos.

@OSUblake Oops, respondi essa última antes de ver sua nova resposta.

O desempenho pode realmente começar a despencar aqui. Você tem que limpar o objeto gráfico, o que redefine tudo.
https://codepen.io/osublake/pen/8217810e590672c5a5327596e33c4b1a?editors=0010

Isso é o que eu temia, o que não é o ideal. Ele começa a se aproximar da lentidão do SVG nativo.

Agora veja esta demonstração usando canvas 2d para gerar as texturas. 3.000 círculos rodando a sólidos 60fps na minha máquina.
https://codepen.io/osublake/full/MoMeMg/

Puta merda, uau! OK! Então, lá vamos nós, que atualmente é a melhor maneira de fazer isso (e com 3000 <canvas> até)!

Por que isso é tão mais rápido? Talvez os implementadores SVG nativos possam aprender com isso (assim como Pixi.js e Two.js)?

Talvez usar essa abordagem no Pixi.js exigiria mudanças na colisão / separação? Haveria uma textura de retângulo em vez de uma malha.

@trusktr O motivo da rapidez é que você desenha na tela uma vez e, em seguida, carrega-o como uma textura na GPU. Nesse exemplo, há uma textura separada gerada para cada raio arredondado para passos de 4px (se bem entendi 😄). A animação é rápida o suficiente para que você não veja a troca de textura.

Você pode fazer coisas semelhantes com a API de desenho do Pixi, armazenando em cache objetos gráficos ( cacheAsBitmap ). Dessa forma, você pode desenhar seus primitivos uma vez e redesenhá-los rapidamente do cache.

Nesse exemplo, há uma textura separada gerada para cada raio arredondado para passos de 4px (se eu entendi corretamente 😄)

Na verdade, é arredondado para incrementos de 0,25. Quanta precisão de subpixel você pode realmente ver?

Se isso for engraçado, então veja como funciona o CanvasTinter da Pixi. Ou como funcionam as animações de folha de sprite. Você sacrifica parte da memória em troca de desempenho e, com uma boa estratégia de cache, isso pode funcionar.

Você pode fazer coisas semelhantes com a API de desenho do Pixi, armazenando em cache objetos Graphics (cacheAsBitmap). Dessa forma, você pode desenhar seus primitivos uma vez e redesenhá-los rapidamente do cache.

Usar cacheAsBitmap pode não parecer bom porque os gráficos terão aliasing. Para obter gráficos suavizados, você precisa usar generateCanvasTexture. De qualquer forma, você acaba com uma tela, mas usando a API de gráficos do Pixi, você não pode fazer coisas simples, como alterar o traço de linha do traço.

Você pode fazer coisas semelhantes com a API de desenho do Pixi, armazenando em cache objetos Graphics (cacheAsBitmap).

Para obter gráficos suavizados, você precisa usar generateCanvasTexture

Com qualquer uma dessas duas opções, posso animar o raio como no seu exemplo @OSUblake ?

(aliás, obrigado pessoal, abrindo meus olhos para técnicas de renderização que eu não tinha imaginado antes).

@trusktr Sim, você só precisa criar muitos objetos gráficos com raios diferentes e criar um mapa das texturas geradas (para que você possa usar uma textura em cache para cada raio). Com cacheAsBitmap você mapearia os objetos gráficos em vez de texturas, mas você não teria o anti-serrilhamento como

Este tipo de animação é a animação de folha de sprite. Quando você pode animar usando transformações, o cache de textura não é necessário. Como se você não se importasse que o traço dos círculos também seja dimensionado, uma simples animação em escala faria isso.

Mas eu concordo, o canvas tem uma API de desenho melhor, então eu a usaria. E para SVG, a hierarquia pode ser dividida em um atlas, como pixi-svg-loader faz (eu acho?). Ou se você quiser uma folha de sprite como uma animação, isso também é possível desenhando os estados da animação na tela.

Talvez usar essa abordagem no Pixi.js exigiria mudanças na colisão / separação? Haveria uma textura de retângulo em vez de uma malha.

Embora não seja tão rápido quanto um polígono, o canvas tem um método para fazer teste de clique em um caminho, isPointInPath . Veja funcionando neste mapa.
https://codepen.io/osublake/pen/dzYzab/?editors=0010

Parece haver um svgloader em three.js, talvez algo que possa ser mapeado para pixi.js
https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/SVGLoader.js

Este problema foi marcado automaticamente como obsoleto porque não teve atividades recentes. Ele será fechado se nenhuma outra atividade ocorrer. Obrigado por suas contribuições.

Este tópico foi bloqueado automaticamente, pois não houve nenhuma atividade recente depois que ele foi fechado. Abra um novo problema para bugs relacionados.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

distinctdan picture distinctdan  ·  3Comentários

softshape picture softshape  ·  3Comentários

lunabunn picture lunabunn  ·  3Comentários

Darker picture Darker  ·  3Comentários

samueller picture samueller  ·  3Comentários