用AA渲染线的最快方法,DirectX中的线宽变化


14

因此,我正在做一些DirectX开发,确切地说是在.NET下使用SharpDX(但DirectX / C ++ API解决方案适用)。我正在寻找使用DirectX在正交投影中渲染线的最快方法(例如,模拟科学应用程序的2D线图)。

我尝试渲染的各种情节的屏幕截图如下: 在此处输入图片说明

这类绘图具有数百万个线段,可变厚度,是否带有每行抗锯齿(或全屏AA开/关)的情况并不少见。我需要非常频繁地更新线条的顶点(例如20次/秒),并尽可能多地卸载GPU。

到目前为止,我已经尝试过:

  1. 软件渲染(例如GDI +)的性能实际上并不差,但显然在CPU上很沉重
  2. Direct2D API-比GDI慢,尤其是在启用抗锯齿功能时
  3. Direct3D10使用此方法在CPU端使用顶点颜色和细分来模拟AA。也很慢(我分析了它,花费了80%的时间用于计算顶点位置)

对于第三种方法,我使用“顶点缓冲区”将三角带发送到GPU,并每200毫秒用新顶点更新一次。100,000个线段的刷新率约为5FPS。我理想地需要数百万!

现在,我在想最快的方法是在GPU上进行细分,例如在Geometry Shader中。我可以将顶点作为线列表发送,也可以打包成纹理,然后在“几何着色器”中解包以创建四边形。或者,只需将原始点发送到像素着色器,然后在像素着色器中完全实现Bresenham Line绘图。我的HLSL是2006年的生锈着色器模型2,所以我不了解现代GPU可以完成的疯狂工作。

所以问题是:-有人做过吗,您有什么建议可以尝试吗?-您对通过快速更新几何来提高性能有什么建议(例如,每20毫秒创建一个新的顶点列表)?

1月21日更新

从那以后,我已经使用LineStrip和Dynamic Vertex Buffers使用Geometry Shader实现了上述方法(3)。现在我以100k点获得100FPS,以1,000,000点获得10FPS。这是一个巨大的改进,但是现在我的填充率和计算能力受到限制,因此我开始考虑其他技术/想法。

  • 线段几何的硬件实例化如何?
  • Sprite Batch呢?
  • 其他面向(像素着色器)的方法呢?
  • 我可以有效地淘汰GPU或CPU吗?

您的意见和建议深表感谢!


1
Direct3D中的本机AA呢?
API-Beast

5
您可以显示一些希望绘制的示例曲线吗?您提到一百万个顶点,但您的屏幕可能没有超过一百万个像素,真的需要这个数量吗?在我看来,您不需要到处都具有完整的数据密度。您是否考虑过LOD?
sam hocevar 2013年

1
链接的第二种方法看起来不错,是使用更新的动态顶点缓冲区还是每次创建一个新的顶点缓冲区?

1
您可能应该使用动态顶点缓冲区(工作量不大,只需告诉您的顶点缓冲区是动态的,映射缓冲区,将数据复制过来,取消映射即可),但是如果您的瓶颈首先是顶点生成,那可能就可以了现在没有太大帮助。不要以为使用GS减轻CPU负载没有任何生气

1
如果顶点数量对于GPU而言太大了,您仍然可以尝试对输入进行下采样-当屏幕要达到几千个像素时,您实际上并不需要一条曲线的亿万线段最多。

Answers:


16

如果您仅要渲染Y = f(X)图形,则建议尝试以下方法。

曲线数据作为纹理数据传递,使其具有持久性,并允许例如进行部分更新glTexSubImage2D。如果需要滚动,甚至可以实现循环缓冲区,并且每帧仅更新几个值。每条曲线均渲染为全屏四边形,所有工作均由像素着色器完成。

单成分纹理内容可能如下所示:

+----+----+----+----+
| 12 | 10 |  5 | .. | values for curve #1
+----+----+----+----+
| 55 | 83 | 87 | .. | values for curve #2
+----+----+----+----+

像素着色器的工作如下:

  • 在数据集空间中找到当前片段的X坐标
  • 例如 具有数据的4个最接近的数据点;例如,如果X值是41.3它会选择40414243
  • 查询纹理的4个Y值(确保采样器不进行任何插值)
  • 将对转换X,Y为屏幕空间
  • 计算从当前片段到三个片段四个点中每个片段的距离
  • 使用距离作为当前片段的Alpha值

您可能希望将4替换为较大的值,具体取决于潜在的缩放级别。

我编写了一个非常快又脏的GLSL着色器,实现了此功能。我可能会在以后添加HLSL版本,但是您应该可以轻松进行转换。可以在下面看到结果,具有不同的行大小和数据密度:

曲线

一个明显的优势是,传输的数据量非常低,而调用调用的次数仅为一个。


这是一个很酷的技术-我在做GPGPU之前就已经了解过了,所以用数据打包纹理是我所了解的,但我并不是考虑过这样做的。最大大小是多少(例如,您可以上传的最大数据集?)。如果您不介意并尝试使用它,我将下载您的代码-我很想看看性能。
ABT博士

@ Dr.ABT数据集大小仅受最大纹理大小限制。我不明白为什么在某些适当的数据布局下数百万个点无法使用。请注意,我的代码肯定不是生产质量,但是如果有任何问题,请随时与我私下联系。
sam hocevar

干杯@SamHocevar-我去试试。自从我编译OpenGL示例思维以来已经有一段时间了!:-)
ABT博士

标记为答案,就像我没有使用纹理加载一样,您展示了一个真实的OpenGL示例,该示例可以在像素着色器上绘制线条并使我们朝正确的方向前进!!:)
ABT博士

4

有GPU Gems一章介绍渲染抗锯齿线:快速预过滤线。基本思想是将每个线段渲染为四边形,并在每个像素处计算像素中心距线段的距离的高斯函数。

这确实意味着将图形中的每个线段绘制为单独的四边形,但是在D3D11中,您当然可以使用几何体着色器和/或实例化来生成四边形,从而将要传输到GPU的数据量减少到仅数据点他们自己。我可能会将数据点设置为StructuredBuffer,以供顶点/几何着色器读取,然后执行一次绘画调用,以指定要绘制的段数。不会有任何实际的顶点缓冲区。顶点着色器将仅使用SV_VertexID或SV_InstanceID来确定要查看的数据点。


嘿,谢谢-是的,我知道那篇文章,不幸的是没有源代码:-( GeoShader + FragShader的前提似乎是这类工作的赢家。有效地将数据传输到GPU将会成为棘手的部分!
ABT博士

嘿@NathanReed回到这个问题-如果我使用Geometry Shader或实例化绘制四边形,那么Point1 / Point2是四边形的相对顶点,我如何在Pixel Shader中计算到Pt1和Pt2之间线的距离?像素着色器是否了解输入几何形状?
ABT博士

@ Dr.ABT数学行的参数必须通过插值器向下发送到像素着色器。像素着色器无法直接访问几何。
内森·里德

我知道,这可以通过发送GeometryShader或实例化的输出来完成吗?:对于额外的信用(如果你有兴趣),我在这里补充问答gamedev.stackexchange.com/questions/47831/...
ABT博士

@ Dr.ABT这与将纹理坐标,法线向量和所有此类东西通常发送到像素着色器的方式完全相同-通过写入顶点/几何着色器的输出进行内插并输入到像素着色器。
内森·里德

0

@ Dr.ABT-对此表示歉意,不是答案。在上述Sam Hocevar的回答中,我没有找到要问的方法。

您能否分享更多有关如何最终实现图表线的详细信息?我同样需要WPF应用程序。预先感谢您可以分享的任何详细信息或代码。


如您所知,它不是一个答案,请编辑并作为注释
MephistonX

我试图这样做,但是原始帖子上没有“添加评论”按钮。
ErcGeek

嗨,ErcGeek,抱歉,我无法共享最终解决方案,因为此信息是我公司专有的。尽管以上示例和建议使我们走上了正确的道路。祝一切顺利!
ABT博士

在获得一定声誉之前,您无法发表评论。所有这些反对票肯定不会为您提供机会。
Mathias Lykkegaard Lorenzen 2013年

不应该因为想要知道最终结果并以唯一可用的方式要求他而受到惩罚。提出了答案。
David Ching
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.