Pixi.js: 真正的SVG支持

创建于 2017-06-29  ·  30评论  ·  资料来源: pixijs/pixi.js

如果 Pixi 能够创建 SVG 的图形层次结构表示(不仅仅是像当前那样加载纹理),那就太好了。

@psyrendust ^ 嘿,你能公关一下你制作的 Pixi 吗? :D

Stale 🙏 Feature Request

最有用的评论

我认为这可以使用 webpack 完成您想要的操作。
https://github.com/blnt1337/pixi-svg-loader

所有30条评论

您可能想查看我制作的这个库:
https://github.com/bigtimebuddy/pixi-svg
https://bigtimebuddy.github.io/pixi-svg/example/

由于 Pixi 中绘图的限制,并非所有 svg 功能都受支持。

@trusktr你能给出一个用例吗? 你的意思是像将组作为容器而将基元集作为精灵吗?

因为这是我一直在想的事情。 可以创建纹理图集并使用来自 SVG 的平移和旋转来创建精灵的层次结构。

我在这种方法中看到的一个问题是锚点(以防我们想要为某些东西设置动画)。 例如 Inkscape 添加锚点作为自定义属性,但它们不在标准 afaik 中。 我的意思的一个例子:

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

该组三个路径的锚点(蓝色矩形的左上角)定义为inkscape:transform-center-xinkscape: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>

虽然我很欣赏你的努力@bigtimebuddy,但我认为在 pixi 中渲染 SVG 原语不是一个好主意。

也检查一下:
https://css-tricks.com/rendering-svg-paths-in-webgl/

我认为这可以使用 webpack 完成您想要的操作。
https://github.com/blnt1337/pixi-svg-loader

@OSUBlake很酷,它确实符合我的意思。 一定要试试 👍

@bigtimebuddy谢谢! 我在那边开了一个新问题。 拥有完整的 Pixi 场景图会很棒。

@RanzQ

@trusktr你能给出一个用例吗? 你的意思是像将组作为容器而将基元集作为精灵吗?

是的,但是原语是Graphics对象而不是精灵。

我在这种方法中看到的一个问题是锚点(以防我们想要为某些东西设置动画)。 例如 Inkscape 添加锚点作为自定义属性,但它们不在标准 afaik 中。 我的意思的一个例子:

我不介意不支持非标准的东西,我可以只接受标准化的 API。 很容易有一个插件来支持特定于inkscape 的东西。

虽然我很欣赏你的努力@bigtimebuddy,但我认为在 pixi 中渲染 SVG 原语不是一个好主意。

你为什么这么认为?

@OSUBlake

我认为这可以使用 webpack 完成您想要的操作。
https://github.com/blnt1337/pixi-svg-loader

这很酷,除了仅限于 Webpack,也仅限于工具化环境,不能在客户端上运行。 我正在寻找可以在运行时(而非构建时)与 Pixi.js 一起使用的 API。


我想要的(我认为,但我不是最专业的 Pixi.js 用户,所以建议使用其他更好的东西,例如使用精灵)是有一个 DisplayObject 场景图,它与用于生成的 SVG DOM 的结构相同Pixi 树来自。 对我来说,这对于操作和动画来说非常强大,而不必每帧重新渲染整个 SVG 来为一个基元(可能是数百或数千)设置动画。

如果开源尚不存在,我想我会做的是采用@bigtimebuddypixi-svg@saschagehlichpixi-svg-graphics ,并修改它们(或使用类似的概念)以创建一个Pixi Graphics树镜像 SVG 树,而不是仅仅绘制到单个Graphics对象上。

@trusktr我明白了,对于基于基元的动画,创建Graphics对象而不是Sprites可能很有用。 但我认为该解决方案可以同时支持Graphics用于简单的 SVG 和Sprites用于更复杂的 SVG。

我认为这不是一个好主意的原因是,已经做了很多努力来创建自定义 SVG 渲染器,根据我的经验,他们总是最终拥有不受支持的东西的TODO

这对艺术家来说将是一个问题,因为人们需要知道哪些功能可以使用,哪些不可以。 我们已经有了一个很好的 SVG 渲染器,即浏览器。 但是如果 SVG 只包含没有效果的简单基元,那么将其解析为Graphics对象可能没问题。

一个精灵效果更好的例子,地图看起来很脆(可能只是缺少抗锯齿)并且由于路径复杂而表现不佳。

使用 canvas 2d 和Path2D api 从 SVG 创建纹理非常容易。

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

路径变形演示
https://codepen.io/osublake/pen/oWzVvb

我打算开发一个更好的 polyfill,因为 Google 的 polyfill 在解析复杂的 SVG 路径时遇到了麻烦。
https://github.com/google/canvas-5-polyfill

@RanzQ

我们已经有了一个很好的 SVG 渲染器,即浏览器。

但它是如此slooooooooow。 它是在 GPU 还是 CPU 中渲染? 例如,对我而言,我体验到的性能无法与使用 Pixi.js 绘制的类似事物的速度相提并论。 在我看来,原生 SVG 引擎做的工作太多了。

与 WebGL 相比,即使是 canvas 2d 也很慢。 在这里比较 WebGL 和 Canvas 之间的区别: http :

我只想绘制 SVG 并让它尽可能快。 到目前为止,至少从概念上讲,使用像 Pixi.js 或 Two.js 这样的 WebGL API 绘制 SVG 似乎是最快的方法。 目前唯一的缺点是并非完全支持所有 SVG 功能。

@OSUBlake

使用 canvas 2d 和 Path2D api 从 SVG 创建纹理非常容易。

Canvas 2D 仍然明显比 WebGL 慢,请参阅我刚刚将两段链接起来的演示。

路径变形演示
https://codepen.io/osublake/pen/oWzVvb

很酷的演示! 在这种情况下,您正在为 PathProxy 中的简单路径设置动画。 这对于用例来说可能足够快。 但是想象一下在一个 SVG 中绘制一堆东西,比如 100 个节点,并为它们设置动画,然后想要整个东西作为环绕球体的纹理。

或者,想象一下该演示中的粒子使用 SVG 完成并为 SVG DOM 节点设置动画,然后在画布中将渲染作为带有drawImage的纹理,最后将其放在 3D webgl 应用程序的四边形上。 会太慢了!

你的演示很快,因为粒子动画是通过 Pixi 在 WebGL 中实现的。

如果使用 Pixi 渲染 SVG 是一个受支持的功能,并且创建了一个镜像 SVG 层次结构的层次结构,那么就有可能将更改映射到display:none <svg>元素( display:none以便它希望阻止浏览器的 SVG 引擎执行工作,因为不需要渲染任何内容)到 Pixi.js 树的更改。

我认为这将是绘制 SVG 的最快方法,因为 Pixi 更快,同时提供了可以由 React、Angular 等操作的 DOM 的便利性。我想要一个我可以操作的 SVG DOM 树,谁来渲染比浏览器缓慢的 SVG 引擎更快。 可能是我要求太高了。 就目前的技术而言,SVG 渲染似乎按照通用标准(我们想要游戏引擎速度)太慢了。

@trusktr

但它是如此slooooooooow。

我的意思是我们可以使用浏览器绘制 SVG 纹理,它很慢但支持所有功能。 你当然不会做那样的动画。 您可以创建纹理图集并在之后为精灵设置动画。 例如,如果您想创建 2D 脊柱角色,那将是您的最佳选择。

我认为这是你所追求的一个例子: https :

任务并不简单,例如动画很复杂,可以在我的旧 Android 手机上缓慢播放,该手机可以很好地播放基于精灵的 Pixi 场景。 我看不出 SVG 和 Pixi 版本有什么区别。 可能只是一个优化问题。

也检查一下: https :

所以在我看来,SVG 有两种不同的需求。 一个具有较少的 SVG 功能,分成基元,另一个具有浏览器渲染的图集,例如,精灵是<g>节点。

另一种方法可能是为矢量图形找到比 SVG 更好的互操作格式或工具。 如果你想要一些可扩展的东西,由于@RanzQ已经阐明的原因,SVG 在 PixiJS 中有其局限性。 SVG 中可用的 Pixi 绘图功能有很多不支持的功能,以至于任何原始绘图翻译都将是二流的。

我推荐的另一种方法是 PixiAnimate (https://github.com/jiborobot/pixi-animate-extension),它是 Adob​​e Animate 的本机扩展(免责声明,我编写了这个),可以很好地导出准确的图形。 此外,您可以使用嵌套符号和图层或动画来创建您想要的任何层次结构。

@bigtimebuddy是否有使用 Animate 从矢量图形创建纹理图集的工作流程? 我一直在寻找这样的工作流程,可以在 UI 辅助下创建 Pixi 场景。

似乎可以在 Animate 的新版本中创建地图集,但您是否为此尝试过您的扩展: http :

@RanzQ是的,PixiAnimate 可以以 TexturePackers 地图集的格式导出单独的图像或精灵表。 但是,矢量形状不会自动转换为纹理。 您需要使用“转换为位图”在 Animate 中执行此操作。

@trusktr

你的演示很快,因为粒子动画是通过 Pixi 在 WebGL 中实现的。

确切地。 我并不是建议使用画布作为主要渲染器。 仅在几何变化时生成纹理/精灵。 对于大多数用例,它应该足够快。 我认为这就是 Two.js 在 WebGL 中进行路径渲染的方式。

使用 Path2D 对象可以提高画布性能,因为浏览器会缓存路径的向量。 这允许您多次使用相同的路径对象,即使使用不同的画布上下文和分辨率。

@OSUBlake

确切地。 我并不是建议使用画布作为主要渲染器。 仅在几何变化时生成纹理/精灵。 对于大多数用例,它应该足够快。 我认为这就是 Two.js 在 WebGL 中进行路径渲染的方式。

是的,这听起来是个好方法。 例如,如果在<circle>元素上修改的唯一属性是cxcy ,这意味着优化将转换现有的网格或精灵而不创建一个新的。

这是 Pixi、Two 和原生 SVG 之间的比较:

为什么 Pixi 明显变慢? 是因为它每帧根据绘制命令重新计算(重新镶嵌或重新光栅化)吗?

在 Two.js 中,Circle 是一个具有 x、y 和半径属性的对象。 很明显,如果只修改 x 和 y,该 API 不需要重新镶嵌/重新光栅化该圆。

如何使用 Pixi 的绘图命令样式进行这种优化并不那么明显。

@trusktr

为什么 Pixi 明显变慢? 是因为它每帧根据绘制命令重新计算(重新镶嵌或重新光栅化)吗?

不。它只是创建了很多三角形,这会降低 GPU 性能。 如果您绘制一个没有线条样式的矩形,您会看到不同之处。 它会将其渲染为精灵,因此性能会好得多。 10,000 个矩形。
https://codepen.io/osublake/pen/PjrbWq/

您是否考虑过使用距离场进行光栅化? 我知道如果你不放大太多,它可以很好地处理字体。 我想知道它是否可以用于动画路径数据。
https://github.com/Tw1ddle/WebGL-Distance-Fields/tree/master/sdf

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

我之前的例子完全不准确,因为我没有意识到 JSBin 很早就脱离了for循环,所以在我的 Macbook Pro 上它只渲染了 500 个圆圈(即使我将n10000 )。 我已经更新了示例,因此它们都渲染了 2000 个圆圈而没有 JSBin 的循环中断:

SVG 示例在仅对圆位置(而不是半径)进行动画处理时仍然是最慢的。

这里是 Two.js 和 SVG 也动画半径:

我没有包含 Pixi.js 版本,因为我不确定如何修改非半径动画版本。 您将如何使用 Pixi.js更新

您将如何使用 Pixi.js 更新无半径动画版本以包含半径动画?

这里的性能可能真的开始急剧下降。 您必须清除图形对象,这会重置所有内容。
https://codepen.io/osublake/pen/8217810e590672c5a5327596e33c4b1a?editors=0010

现在看看这个使用 canvas 2d 生成纹理的演示。 在我的机器上以稳定的 60fps 运行 3,000 个圆圈。
https://codepen.io/osublake/full/MoMeMg/

好吧,无论如何,我认为这有一个很好的用例,如示例所示:在某些情况下,它在 WebGL 中可以快得多。

@OSUBlake哎呀,我在看到你的新回复之前回复了最后一个。

这里的性能可能真的开始急剧下降。 您必须清除图形对象,这会重置所有内容。
https://codepen.io/osublake/pen/8217810e590672c5a5327596e33c4b1a?editors=0010

这就是我所担心的,这并不理想。 它开始接近原生 SVG 缓慢。

现在看看这个使用 canvas 2d 生成纹理的演示。 在我的机器上以稳定的 60fps 运行 3,000 个圆圈。
https://codepen.io/osublake/full/MoMeMg/

天啊,哇! 好的! 所以,我们走了,这是目前最好的方法(甚至 3000 <canvas> )!

为什么这么快? 也许原生 SVG 实现者可以从中学习(以及 Pixi.js 和 Two.js)?

也许在 Pixi.js 中使用这种方法需要更改碰撞/拾取? 会有一个矩形纹理而不是网格。

@trusktr快速的原因是您在画布上绘制一次,然后将其作为纹理上传到 GPU。 在那个例子中,为每个半径生成了一个单独的纹理,四舍五入到 4px 步长(如果我理解正确的话😄)。 动画足够快,所以你不会看到纹理交换。

您可以通过缓存 Graphics 对象 ( cacheAsBitmap ) 使用 Pixi 的绘图 API 执行类似的操作。 这样您就可以一次绘制基元并从缓存中快速重新绘制它们。

在那个例子中,为每个半径生成了一个单独的纹理,四舍五入到 4px 步长(如果我理解正确的话😄)

它实际上四舍五入到 0.25 增量。 你实际能看到多少亚像素精度?

如果这很有趣,那么请查看 Pixi 的 CanvasTinter 是如何工作的。 或者精灵表动画是如何工作的。 你牺牲了一些内存来换取性能,有了一个好的缓存策略它就可以工作了。

您可以通过缓存 Graphics 对象 (cacheAsBitmap) 使用 Pixi 的绘图 API 做类似的事情。 这样您就可以一次绘制基元并从缓存中快速重新绘制它们。

使用 cacheAsBitmap 可能看起来不太好,因为图形会有锯齿。 要获得抗锯齿图形,您需要使用 generateCanvasTexture。 所以无论哪种方式你最终都会得到一个画布,但是使用 Pixi 的图形 api 你不能做简单的事情,比如改变笔划的线段。

您可以通过缓存 Graphics 对象 (cacheAsBitmap) 使用 Pixi 的绘图 API 做类似的事情。

要获得抗锯齿图形,您需要使用 generateCanvasTexture

使用这两个选项中的任何一个,我可以像在您的示例@OSUBlake 中那样为半径设置动画吗?

(顺便说一句,谢谢你们,让我睁开眼睛看到我以前从未想象过的渲染技术)。

@trusktr是的,您只需要创建许多具有不同半径的 Graphics 对象并创建生成纹理的贴图(这样您就可以为每个半径使用缓存的纹理)。 使用cacheAsBitmap您可以映射 Graphics 对象而不是纹理,但您不会像@OSUblake所说的那样具有抗锯齿

这种动画是精灵片动画。 当您可以使用变换制作动画时,则不需要纹理缓存。 就像如果您不关心圆圈的笔划也可以缩放一样,一个简单的缩放动画就可以做到。

但我同意,canvas 有更好的绘图 API,所以我会使用它。 对于 SVG,层次结构可以拆分为一个图集,就像pixi-svg-loader那样(我认为?)。 或者,如果您想要像动画一样的精灵表,也可以通过在画布上绘制动画状态来实现。

也许在 Pixi.js 中使用这种方法需要更改碰撞/拾取? 会有一个矩形纹理而不是网格。

虽然不如多边形快,但画布确实有方法在路径isPointInPath上进行命中测试。 看到它在这张地图上工作。
https://codepen.io/osublake/pen/dzYzab/?editors=0010

Three.js里面好像有个svgloader,说不定什么可以映射到pixi.js
https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/SVGLoader.js

此问题已自动标记为陈旧,因为它最近没有活动。 如果没有进一步的活动发生,它将被关闭。 感谢你的贡献。

由于关闭后没有任何近期活动,因此该线程已自动锁定。 请为相关错误打开一个新问题。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

st3v0 picture st3v0  ·  3评论

courtneyvigo picture courtneyvigo  ·  3评论

YuryKuvetski picture YuryKuvetski  ·  3评论

gigamesh picture gigamesh  ·  3评论

Makio64 picture Makio64  ·  3评论