使用 OpenGL(和 OpenGL ES)渲染 SVG

Posted

技术标签:

【中文标题】使用 OpenGL(和 OpenGL ES)渲染 SVG【英文标题】:Rendering SVG with OpenGL (and OpenGL ES) 【发布时间】:2011-09-11 08:57:03 【问题描述】:

我目前正在研究使用 OpenGL 和 OpenGL ES 从 SVG 文件渲染矢量图的可能性。我打算针对 Windows 和 android。我理想的解决方案是拥有一个最小的 C 库,可以从给定的 SVG 文件生成多边形三角剖分。然后,这将生成标准的 OpenGL 或 OpenGL ES 调用,并在重绘时使用显示列表或 vbo 进行优化。我会简单地绘制一个显示列表来在平移和旋转之后绘制矢量图像,让我可以将它与其他 OpenGL 调用混合使用。

到目前为止,我看到的建议是首先使用 QT 或 Cairo。 - 这不是一个选项,因为我希望在没有臃肿库的情况下管理我自己的 OpenGL 上下文(在我想要实现的上下文中)。这也不适合 Android。

第二个选项是使用渲染到纹理的库。虽然这对于静态矢量图形来说可能没问题,但对于经常发生缩放和旋转的游戏来说,这不是一个有效或可行的选择。

第三,可以使用 OpenVG。 OpenVG规范(ShivaVG等)有一些开源实现,但我还没有找到一个能够在运行时从给定的SVG文件生成适当的OpenVG调用的库,我看不出如何优化它我们可能希望使用显示列表或 vbo。

这三种方法都有局限性。如果不存在其他解决方案,我认为最有希望的选择是使用 OpenVG 实现。所以我的问题是,有没有图书馆可以做我想要的,或者接近我想要的?如果没有,是否有充分的理由不这样做?而是从头开始尝试这样做会更好吗?

【问题讨论】:

解析 svg 文件的路径并不困难。检查以下内容以绘制二次贝塞尔曲线。 opengl.org/resources/code/samples/redbook/bezcurve.c @Grady glEvalCoord 在 OpenGL ES 中不存在; GLU 也不是,它的 tesselator 是至关重要的,例如凸多边形。 @me232 好问题,点赞和收藏 +1 良好的研究和精心设计的问题 是的,你是对的,我被最小的 C 库部分抛出了。 基本上也是***.com/questions/1027179/…的翻版 【参考方案1】:

我的答案是关于使用 OpenGL 显示矢量图形,因为这个问题的所有解决方案都可以特别支持相当微不足道的 SVG,尽管没有一个支持动画 SVG (SMIL)。由于没有关于动画的内容,我认为这个问题只暗示了静态 SVG。

首先,我不会为任何 OpenVG 烦恼,即使是 MonkVG,它可能是最现代的,尽管实现不完整。 OpenVG 委员会已于 2011 年解散,大多数(如果不是全部)实现都是废弃软件或充其量是遗留软件。

自 2011 年以来,最先进的是 Mark Kilgard 的宝贝 NV_path_rendering,它目前只是一个供应商 (Nvidia) 扩展,您可能已经从它的名称中猜到了。这方面的资料很多:

https://developer.nvidia.com/nv-path-rendering Nvidia hub,但登录页面上的某些材料不是最新的 http://developer.download.nvidia.com/devzone/devcenter/gamegraphics/files/opengl/gpupathrender.pdf Siggraph 2012 论文 http://on-demand.gputechconf.com/gtc/2014/presentations/S4810-accelerating-vector-graphics-mobile-web.pdf GTC 2014 演讲 http://www.opengl.org/registry/specs/NV/path_rendering.txt官方扩展文档

您当然可以加载 SVG 等 https://www.youtube.com/watch?v=bCrohG6PJQE。它们还支持路径的 PostScript 语法。您还可以将路径渲染与其他 OpenGL (3D) 内容混合使用,如下所示:

https://www.youtube.com/watch?v=FVYl4o1rgIs https://www.youtube.com/watch?v=yZBXGLlmg2U

NV_path_rendering 现在由 Google 的 Skia 库在后台使用(如果可用)。 (Nvidia 在 2013 年末和 2014 年贡献了代码。)其中一位 cairo 开发人员(也是英特尔员工)似乎也喜欢它http://lists.cairographics.org/archives/cairo/2013-March/024134.html,尽管我 [尚未] 知道为 cairo 做出的任何具体努力使用 NV_path_rendering。

NV_path_rendering 对固定管道有一些较小的依赖性,因此在 OpenGL ES 中使用它可能会有点麻烦。此问题记录在上面链接的官方扩展文档中。有关解决方法,请参见例如 Skia/Chromium 所做的事情:https://code.google.com/p/chromium/issues/detail?id=344330

目前正在开发和维护的NanoVG 是一个拥有更少(或完全没有)供应商支持或学术浮华的新贵。 (https://github.com/memononen/nanovg) 鉴于 OpenGL 上的 2D 库的数量随着时间的推移来来去去,在我看来,您正在押注使用主要供应商不支持的东西。

【讨论】:

【参考方案2】:

查看MonkVG 在 OpenGL ES 之上的类似 OpenVG 的 API 实现。

此外,对于 OpenVG (MonkVG) 之上的 SVG 渲染,请查看 MonkSVG。

MonkVG 专为 ios、OSX 和 Android 平台构建。

我是这两个库的作者,很乐意回答任何问题。

【讨论】:

嗨,迈卡。我找到了 MonkVG 的 Windows 项目并设法用 VS2010 构建它。有没有为 Windows 编译的工作示例?我试图遵循这个例子的尝试失败了。我手动创建自己的窗口和上下文,但我想如果您有基于它的示例,基于 GLUT 的解决方案就可以了。【参考方案3】:

需要说的是,使用 OpenGL 或 OpenGL ES 渲染 SVG 或 OpenVG 从根本上来说是个坏主意。 OpenVG 的实现如此缓慢且大部分被废弃是有原因的。按照 OpenGL 的要求,将路径(所有 SVG/OpenVG 渲染的基础)细分为三角形列表的过程从根本上说是缓慢且低效的。它基本上需要在 3D 渲染管道中插入排序/搜索算法,这会削弱性能。还有一个问题是需要动态内存分配方案,因为数据集的大小是未知的,因为 SVG 对路径几何的复杂性没有限制。一个非常糟糕的设计。

SVG 和 OpenVG 是由对现代 3D 图形硬件引擎的实际工作原理(三角形列表)知之甚少的开发人员创建的。它们的创建是为了作为 Adob​​e Flash 的开放替代品,Adobe Flash 也具有相同的有缺陷的架构,这使得 Flash 在业界因不可预测的性能而受到谴责。

我的建议是重新考虑您的设计并直接使用 OpenGL 三角形列表。您可能需要编写更多代码,但您的应用程序的性能将提高大约一千倍,并且您可以比其他人更轻松地调试代码。

【讨论】:

请注意:使用 OpenGL 绘制 SVG 的方法有很多,而将路径细分为三角形可能是其中最糟糕的一种。使用着色器怎么样? @AdrianMaire 你知道现有的任何基于着色器的方法吗? 我不记得有任何现成的库。我所指的方法是绘制一个覆盖整个路径的大矩形,然后对于每个像素,检测它是否在内部/外部/边界,并计算它的颜色。可以应用超级采样和其他技术。我敢肯定有关于这方面的论文。【参考方案4】:

我目前正在研究使用 OpenGL 和 OpenGL ES 从 SVG 文件渲染矢量图形的可能性。我打算针对 Windows 和 Android。我的理想解决方案 将有一个最小的 C 库,从给定的生成多边形三角剖分 SVG 文件。这将生成标准的 OpenGL 或 OpenGL ES 调用,并使用显示 list 或 vbo 用于重绘时的优化。我会简单地绘制一个显示列表来绘制 平移和旋转后的矢量图像,允许我将其与其他 OpenGL > 调用混合使用。

如果您只想将 SVG 矢量形状转换为 OpenGL|ES,那么我建议您自己执行解析器和逻辑。请注意,SVG 是一个庞大的规范,具有不同的功能,例如绘制服务器(渐变、图案 ...)、引用、过滤器、剪辑、字体处理、动画、脚本、链接等。

如果您想要完整的 svg 支持,那么http://code.google.com/p/enesim 上有一个名为 egueb(尤其是 esvg)的库,它使用 enesim(具有软件和 opengl 后端的渲染库)进行绘图。在大多数情况下,它使用着色器并将所有内容渲染到纹理中,该库非常灵活,可让您适应您的特定需求,例如修改渲染场景、变换场景等。因为 gl 绘制总是在纹理中完成。

到目前为止,我看到的建议是首先使用 QT 或 Cairo。 - 这不是一个选项 鉴于我希望在没有臃肿库的情况下管理自己的 OpenGL 上下文(在 我要达到的目标的背景)。这也不适合 Android。

第二个选项是使用渲染到纹理的库。虽然这对 静态矢量图形,对于缩放的游戏来说,这不是一个有效或可行的选择 并且经常发生轮换。

在 gl 后端的特殊情况下,enesim 不会创建 GLX(或任何其他依赖于窗口的上下文),您必须提供它,因此它可以完美地适应您的情况,因为它只使用 GL 调用。

唯一的缺点是该库在 gl 支持或完整的 SVG 规范支持方面还不完整,但根据您的需要,在我看来这是一个不错的选择。

【讨论】:

您使用什么算法将三次贝塞尔曲线(路径)转换为 OpenGL?抗锯齿呢【参考方案5】:

来自http://shivavg.svn.sourceforge.net/viewvc/shivavg/trunk/src/shPipeline.c?revision=14&view=markup:

static void shDrawVertices(SHPath *p, GLenum mode)

int start = 0;
int size = 0;

/* We separate vertex arrays by contours to properly
handle the fill modes */
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(SHVertex), p->vertices.items);

while (start < p->vertices.size) 
size = p->vertices.items[start].flags;
glDrawArrays(mode, start, size);
start += size;


glDisableClientState(GL_VERTEX_ARRAY);

所以它确实使用了 VBO。因此,我建议您制作自己的 SVG 解析器/使用预制解析器,然后将调用转发给 ShivaVG。

您仍然有 ShivaVG 使用 C(而不是 Java)并创建 opengl 上下文(而不是 opengles,如果我正确阅读代码)的问题。因此,即使您使用 Android 的 NDK 编译它,您也必须修改代码(例如,我已经看到了一些 glVertex3f,但它们似乎并不需要......希望最好)。当然,另一个选项是将代码从 C 移植到 Java。也许没有你想象的那么痛苦。

祝你好运!

【讨论】:

谢谢,我会看看这个。鉴于对硬件加速矢量图形的需求以及 OpenVG 在设计时考虑到移动设备这一事实,我感到惊讶的是,没有一种开箱即用的实现。我知道一个用 C# 编写的项目试图做一些非常相似的事情并获得成功的结果http://neuronspew.wordpress.com/category/svg-game-engine-project/ 如果我能做到这一点,我一定会公开我的代码。 谢谢!请在完成后更新此主题? ShivaVG 不使用 VBO。使用 glVertexPointer() 并不意味着使用 VBO;在这段代码中,顶点取自 p->vertices.items 指向的内存。我知道这一点是因为在调用此函数时必须调试 VBO 被程序的另一部分绑定的情况。【参考方案6】:

你可以看看AmanithVG,他们似乎已经实现了一个很好的路径->三角形管道。我试过 iOS GL Tiger 的例子,看来三角测量并不是真正的瓶颈。

【讨论】:

以上是关于使用 OpenGL(和 OpenGL ES)渲染 SVG的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL学习随笔-- OpenGL ES 2.0渲染管线

OpenGL ES 太好玩了图形渲染管线

OpenGL ES 太好玩了图形渲染管线

结合 UIView 动画块和 OpenGL ES 渲染

我的OpenGL学习进阶之旅关于OpenGL ES 绘制中使用到的 Android中GLSurfaceView的两种渲染模式

我的OpenGL学习进阶之旅关于OpenGL ES 绘制中使用到的 Android中GLSurfaceView的两种渲染模式