Direct3D 中的高效线条绘制(Transformation2D?)
背景:我使用 DirectX 的 SlimDX C# 包装器,并使用 Sprite 类(传统上来自底层 dll 中的 Direct3DX 扩展)绘制许多 2D 精灵。 我一次在屏幕上绘制数百个精灵,性能非常棒 - 在我的四核上,它为我的整个游戏使用了大约 3-6% 的处理器,包括 10,000 多个对象的逻辑,ai第二个线程上的例程等等。很明显,精灵正在使用完整的硬件加速进行绘制,一切都应该如此。
问题:当我开始引入对 Line 类的调用时,问题就出现了。 一旦我绘制 4 条线(用于拖动选择框),处理器使用率就会飙升至 13-19%。 这只有四行!
我尝试过的事情:
- 关闭和打开线路抗锯齿。
- 关闭和打开 GLLines。
- 在我的绘图调用周围手动调用 line.begin 和 line.end 。
- 省略对 line.begin 和 line.end 的所有调用。
- 确保我对 line.draw 的调用不在 sprite.begin / sprite.end 块内。
- 在 sprite.begin / sprite.end 块内调用 line.draw。
- 渲染 4 行,或渲染 300。
- 关闭所有精灵和文本渲染,只保留 4 行的线条渲染(看看这是否是某种模式更改问题)。
- 以上的大多数组合。
一般来说,这些都不会对性能产生重大影响。 #3 可能减少了 2% 的处理器使用率,但即便如此,它仍然比应有的水平高出 8% 或更多。 最奇怪的是,上面的#7 对性能的影响绝对为零——4 行和 300 行一样慢。我唯一能想到的是,由于某种原因,它是在软件中运行的,和/或它导致显卡在某种绘图模式之间不断地来回切换。
矩阵方法:
如果有人知道上述问题的任何解决方案,那么我很想听听!
但我假设这可能只是 directx 内部的一个问题,所以我一直在寻求另一条路线——制作我自己的基于精灵的线路。 本质上,我有一个 1 像素的白色图像,我使用漫反射颜色和变换来绘制线条。 从性能角度来看,这是有效的——像这样绘制 300 条“线”,使我的处理器利用率达到 3-6% 的性能范围,这正是我在四核上寻找的性能范围。
我的像素拉伸线技术有两个问题,我希望对变换更了解的人可以帮助我解决。 这是我当前的水平线代码:
public void DrawLineHorizontal( int X1, int X2, int Y, float HalfHeight, Color Color )
{
float width = ( X2 - X1 ) / 2.0f;
Matrix m = Matrix.Transformation2D( new Vector2( X1 + width, Y ), 0f, new Vector2( width, HalfHeight ),
Vector2.Zero, 0, Vector2.Zero );
sprite.Transform = m;
sprite.Draw( this.tx, Vector3.Zero, new Vector3( X1 + width, Y, 0 ), Color );
}
这是有效的,因为它在屏幕上的正确位置绘制了大部分正确尺寸的线条。 然而,事情似乎向右移动,这很奇怪。 我不太确定我的矩阵方法是否正确:我只想将 1x1 精灵水平缩放一定数量的像素,并垂直缩放不同数量的像素。 然后我需要能够将它们定位 - 通过中心点就可以了,我认为这就是我必须做的,但如果我可以将其定位在左上角,那就更好了。 这看起来是一个简单的问题,但我的矩阵知识很薄弱。
这将使纯水平线和纯垂直线对我有用,这是大部分的战斗。 我可以接受这一点,并在我当前使用倾斜线的位置使用其他类型的图形。 但如果有一种方法可以让我使用这种拉伸像素方法绘制有角度的线条,那就太好了。 换句话说,例如从 1,1 到 7,19 画一条线。 通过矩阵旋转等,这似乎是可行的,但除了猜测和检查之外,我不知道从哪里开始,这将花费很长时间。
非常感谢任何和所有的帮助!
Background: I'm using the SlimDX C# wrapper for DirectX, and am drawing many 2D sprites using the Sprite class (traditionally from the Direct3DX extension in the underlying dlls). I'm drawing multiple hundreds of sprites to the screen at once, and the performance is awesome -- on my quad core, it's using something like 3-6% of the processor for my entire game, including logic for 10,000+ objects, ai routines on a second thread, etc, etc. So clearly the sprites are being drawing using full hardware acceleration, and everything is as it should be.
Issue: The problem comes when I start introducing calls to the Line class. As soon as I draw 4 lines (for a drag selection box), processor usage skyrockets to 13-19%. This is with only four lines!
Things I have tried:
- Turning line antialiasing off and on.
- Turning GLLines off and on.
- Manually calling the line.begin and line.end around my calls to draw.
- Omitting all calls to line.begin and line.end.
- Ensuring that my calls to line.draw are not inside a sprite.begin / sprite.end block.
- Calling line.draw inside a sprite.begin / sprite.end block.
- Rendering 4 lines, or rendering 300.
- Turning off all sprite and text rendering, and just leaving the line rendering for 4 lines (to see if this was some sort of mode-changing issue).
- Most combinations of the above.
In general, none of these had a significant impact on performance. #3 reduced processor usage by maybe 2%, but even then it's still 8% or more higher than it should be. The strangest thing is that #7 from above had absolutely zero impact on performance -- it was just as slow with 4 lines as it was with 300. The only thing that I can figure is that this is being run in software for some reason, and/or that it is causing the graphics card to continually switch back and forth between some sort of drawing modes.
Matrix Approach:
If anyone knows of any fix to the above issue, then I'd love to hear it!
But I'm under the assumption that this might just be an issue inside of directx in general, so I've been pursuing another route -- making my own sprite-based line. Essentially, I've got a 1px white image, and I'm using the diffuse color and transforms to draw the lines. This works, performance-wise -- drawing 300 of the "lines" like this puts me in the 3-6% processor utilization performance range that I'm looking for on my quad core.
I have two problems with my pixel-stretch line technique, which I'm hoping that someone more knowledgeable about transforms can help me with. Here's my current code for a horizontal line:
public void DrawLineHorizontal( int X1, int X2, int Y, float HalfHeight, Color Color )
{
float width = ( X2 - X1 ) / 2.0f;
Matrix m = Matrix.Transformation2D( new Vector2( X1 + width, Y ), 0f, new Vector2( width, HalfHeight ),
Vector2.Zero, 0, Vector2.Zero );
sprite.Transform = m;
sprite.Draw( this.tx, Vector3.Zero, new Vector3( X1 + width, Y, 0 ), Color );
}
This works, insofar as it draws lines of mostly the right size at mostly the right location on the screen. However, things appear shifted to the right, which is strange. I'm not quite sure if my matrix approach is right at all: I just want to scale a 1x1 sprite by some amount of pixels horizontally, and a different amount vertically. Then I need to be able to position them -- by the center point is fine, and I think that's what I'll have to do, but if I could position it by upper-left that would be even better. This seems like a simple problem, but my knowledge of matrices is pretty weak.
This would get purely-horizontal and purely-vertical lines working for me, which is most of the battle. I could live with just that, and use some other sort of graphic in locations which I am currently using angled lines. But it would be really nice if there was a way for me to draw lines that are angled using this stretched-pixel approach. In other words, draw a line from 1,1 to 7,19, for instance. With matrix rotation, etc, it seems like this is feasible, but I don't know where to even begin other than guessing and checking, which would take forever.
Any and all help is much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
听起来像是管道停顿。 您正在渲染精灵和渲染线之间切换某种模式,这会强制显卡在开始新图元之前清空其管道。
在添加线条之前,这些精灵都是您渲染的吗?或者屏幕上是否已经使用其他模式渲染了其他元素?
it sounds like a pipeline stall. You're switching some mode between rendering sprites and rendering lines, that forces the graphics card to empty its pipeline before starting with the new primitive.
Before you added the lines, were those sprites all you rendered, or were there other elements on-screen, using other modes already?
好吧,经过多次实验,我已经成功地让水平线发挥作用了。 这没有我之前看到的奇怪的偏移; 同样的原理也适用于垂直线。 这比 line 类具有大大更好的性能,所以这就是我将用于水平和垂直线的。 这是代码:
我想要一个也适用于有角度的线的版本(如上所述)。 对此有何建议?
Okay, I've managed to get horizontal lines working after much experimentation. This works without the strange offsetting I was seeing before; the same principle will work for vertical lines as well. This has vastly better performance than the line class, so this is what I'll be using for horizontal and vertical lines. Here's the code:
I'd like to have a version of this that would work for lines at angles, too (as mentioned above). Any suggestions for that?