10

我是一个团队的一员,该团队创建了一个工具来查看 C#/WPF 中非常大且高度互连的图形并与之交互。查看图表并与之交互是通过一个自定义控件完成的,该控件接受一组绘图视觉对象并将它们显示在画布上。图中的节点可能具有使用我们的编辑器创建的自定义形状。当前的控件运行良好,并且与我们的程序相当耦合,但是在考虑更大的图(20,000 多个节点和大量连接)时,存在对性能的合理担忧。

在做了一些研究之后,这两种方法似乎是:

  • 将图形绘制到 WriteableBitmap 或 InteropBitmap 的 GDI+ 路径。
  • SlimDX 或 DirectX 变体(托管在 D3DImage 中)


鉴于这两种截然不同的方法,最好考虑哪种路线:

  • 即使在查看整个图表时,与图表的交互也必须快速。
  • 更新视觉效果应该很快(颜色或大小变化)
  • 命中测试必须快速(点和矩形)。
  • 开发必须及时完成。

你会使用哪种方法,为什么?

编辑:
看起来有人问了类似的问题,但没有回答。

4

3 回答 3

10

我将 GDI 用于我的制图应用程序。虽然 GDI+ 比 DirectX 慢,但我发现有很多东西和技巧可以用来加快速度。大量 CPU 用于在绘制数据之前准备数据,因此 GDI 不应该是那里唯一的瓶颈。

需要注意的事项(这些也足以适用于其他图形引擎):

  1. 首先:测量。使用分析器查看代码中真正的瓶颈是什么。
  2. 重用 GDI 原语。这是至关重要的。如果您必须绘制 100,000 个看起来相同或相似的图形对象,请使用相同PenBrush。创建这些图元的成本很高。
  3. 缓存渲染数据- 例如:如果不需要,不要重新计算 gfx 元素位置。
  4. 平移/缩放时,以较低的 GDI+ 质量绘制场景(并且没有昂贵的 GDI 操作)。有许多Graphics对象设置可以降低质量。用户停止平移后,绘制高质量的场景。
  5. 很多很多可以提高性能的小东西。我已经开发这个应用程序 2-3 年(或者它已经 4 年了?)现在我仍然找到改进的方法:)。这就是分析很重要的原因 - 代码更改,这会影响性能,因此您需要分析新代码。

另一件事:我没有使用过 SlimDX,但我确实尝试过 Direct2D(我指的是Microsoft.WindowsAPICodePack.DirectX.Direct2D1)。在我的情况下,性能比 GDI+ 快得多,但我在渲染位图时遇到了一些问题,而且从来没有时间找到合适的解决方案。

于 2012-04-25T07:02:17.637 回答
3

我最近将一些绘图代码移植到 DirectX 并且对结果非常满意。我们主要使用 bit-bashing 渲染位图,并且看到可以以分钟为单位测量的渲染时间减少到大约 1-2 秒。

这不能直接与您的使用情况进行比较,因为我们已经使用 SlimDX 从 C++ 中的 bit-bashing 到 C# 中的 Direct3D,但我想您会看到性能优势,即使它们不是我们的数量级。重看。

我建议你看看使用 Direct2D 和 SlimDX。您将需要使用 DirectX 10.1,因为 Direct2D 出于某种原因与 DirectX 11 不兼容。如果您在 WPF 中使用过绘图 API,那么您已经熟悉 Direct2D,因为据我所知,它的 API 基于 WPF 绘图 API。Direct2D 的主要问题是缺乏文档,而且它只适用于 Vista 以后的版本。

我没有尝试过 DirectX 10/WPF 互操作,但我相信这是可能的 (http://stackoverflow.com/questions/1252780/d3dimage-using-dx10)

编辑:我想我会从我们绘制简单多边形的代码中给你一个比较。首先是WPF版本:

        StreamGeometry geometry = new StreamGeometry();

        using (StreamGeometryContext ctx = geometry.Open())
        {
            foreach (Polygon polygon in mask.Polygons)
            {
                bool first = true;

                foreach (Vector2 p in polygon.Points)
                {
                    Point point = new Point(p.X, p.Y);

                    if (first)
                    {
                        ctx.BeginFigure(point, true, true);
                        first = false;
                    }
                    else
                    {
                        ctx.LineTo(point, false, false);
                    }
                }
            }
        }

现在是 Direct2D 版本:

        Texture2D maskTexture = helper.CreateRenderTexture(width, height);

        RenderTargetProperties props = new RenderTargetProperties
        {
            HorizontalDpi = 96,
            PixelFormat = new PixelFormat(SlimDX.DXGI.Format.Unknown, AlphaMode.Premultiplied),
            Type = RenderTargetType.Default,
            Usage = RenderTargetUsage.None,
            VerticalDpi = 96,
        };

        using (SlimDX.Direct2D.Factory factory = new SlimDX.Direct2D.Factory())
        using (SlimDX.DXGI.Surface surface = maskTexture.AsSurface())
        using (RenderTarget target = RenderTarget.FromDXGI(factory, surface, props))
        using (SlimDX.Direct2D.Brush brush = new SolidColorBrush(target, new SlimDX.Color4(System.Drawing.Color.Red)))
        using (PathGeometry geometry = new PathGeometry(factory))
        using (SimplifiedGeometrySink sink = geometry.Open())
        {
            foreach (Polygon polygon in mask.Polygons)
            {
                PointF[] points = new PointF[polygon.Points.Count()];
                int i = 0;

                foreach (Vector2 p in polygon.Points)
                {
                    points[i++] = new PointF(p.X * width, p.Y * height);
                }

                sink.BeginFigure(points[0], FigureBegin.Filled);
                sink.AddLines(points);
                sink.EndFigure(FigureEnd.Closed);
            }

            sink.Close();
            target.BeginDraw();
            target.FillGeometry(geometry, brush);
            target.EndDraw();
        }

如您所见,Direct2D 版本的工作量稍大一些(并且依赖于我编写的一些辅助函数),但实际上非常相似。

于 2012-04-25T19:16:50.117 回答
1

让我尝试列出每种方法的优缺点——这可能会让您对使用哪种方法有所了解。

GDI 专业人士

  • 易于绘制矢量形状
  • 无需包含额外的库

GDI 缺点

  • 比 DX 慢
  • 需要限制“花式”绘图(渐变等),否则可能会减慢速度
  • 如果图表需要交互 - 可能不是一个很好的选择

SlimDX 优点

  • 可以做一些花哨的绘图,同时比 GDI 更快
  • 如果绘图是交互式的 - 这种方法会更好
  • 由于您绘制了基元,因此您可以控制每个缩放级别的质量

SlimDX 缺点

  • 绘制简单的形状并不容易——您需要编写自己的抽象或使用帮助您绘制形状的库
  • 使用 GDI 并不那么简单,尤其是如果您以前没有使用过它

也许我忘了在这里放更多,但也许这些对初学者有用?

-一个。

于 2012-04-23T20:32:16.393 回答