我正在编写一个粒子引擎,并注意到它的速度比应有的慢得多(我编写的高度未经优化的3D C++粒子引擎能够以60 fps渲染50k粒子,这一粒子在1.2k左右下降到32 fps. .),我对代码做了一些分析,假设渲染粒子或旋转是CPU占用最多的操作,但是我发现实际上图形对象的这两个小属性实际上占据了我性能的70%以上....
public void RotateParticle(Graphics g, RectangleF r, RectangleF rShadow, float angle, Pen particleColor, Pen particleShadow) { //Create a matrix Matrix m = new Matrix(); PointF shadowPoint = new PointF(rShadow.Left + (rShadow.Width / 1), rShadow.Top + (rShadow.Height / 1)); PointF particlePoint = new PointF(r.Left + (r.Width / 1), r.Top + (r.Height / 2)); //Angle of the shadow gets set to the angle of the particle, //that way we can rotate them at the same rate float shadowAngle = angle; m.RotateAt(shadowAngle, shadowPoint); g.Transform = m; //rotate and draw the shadow of the Particle g.DrawRectangle(particleShadow, rShadow.X, rShadow.Y, rShadow.Width, rShadow.Height); //Reset the matrix for the next draw and dispose of the first matrix //NOTE: Using one matrix for both the shadow and the partice causes one //to rotate at half the speed of the other. g.ResetTransform(); m.Dispose(); //Same stuff as before but for the actual particle Matrix m2 = new Matrix(); m2.RotateAt(angle, particlePoint); //Set the current draw location to the rotated matrix point //and draw the Particle g.Transform = m2; g.DrawRectangle(particleColor, r.X, r.Y, r.Width, r.Height); m2.Dispose(); }
杀死我的表现的具体是这些方面:
g.Transform = m; g.Transform = m2;
一点点背景,图形对象从painteventargs中获取,然后在渲染粒子方法中将粒子渲染到屏幕上,该方法调用此方法进行任何旋转,多线程不是解决方案,因为图形对象不能在多个线程之间共享.这是我运行的代码分析的链接,以便您可以看到正在发生的事情:
https://gyazo.com/229cfad93b5b0e95891eccfbfd056020
我有点认为这是一个无法真正帮助的东西,因为看起来房产本身正在摧毁性能,而不是我实际做过的任何事情(尽管我确信还有改进的余地),特别是因为dll class calls是使用最大的cpu功率.无论如何,任何帮助都会在尝试优化这一点时非常感激...也许我只是启用/禁用旋转来提高性能,我们会看到......
好吧,您应该在看到的配置文件结果上花些时间。分配Transform属性时,还有其他事情发生。您可以通过注意到ResetTransform()不花费任何费用来推断出某些原因。当然没有意义,该方法还会更改Transform属性。
并请注意,应该是DrawRectangle()应该是昂贵的方法,因为这实际上是将踏板踩到金属上并生成真实的绘制命令的方法。我们无法从您的屏幕截图中看到费用,该费用不能超过30%。这还远远不够。
我认为您在这里看到的是GDI / plus的晦涩功能,它会批量绘制绘图命令。换句话说,它在内部生成绘制命令的列表,并且直到需要时才将其传递给视频驱动程序。本机winapi具有显式强制刷新该列表的功能,它是 GdiFlush()。但是,.NET Graphics类未公开该内容,它是自动完成的。
因此,一个颇具吸引力的理论是,当您分配Transform属性时,GDI +内部调用GdiFlush()。所以您看到的成本是的成本实际上是先前DrawRectangle()调用的成本。
您需要为它提供更多的批处理机会,以取得成功。非常喜欢Graphics类方法,该方法使您可以绘制大量项目。换句话说,不要绘制每个单独的粒子,而是绘制许多。您会喜欢DrawRectangles(),DrawLines(),DrawPath()。不幸的是,没有DrawPolygons()(您真正喜欢的那个),从技术上讲,您可以选择PolyPolygon(),但这很难实现。
如果我的理论不正确,请注意您不需要Graphics.Transform。您也可以使用Matrix.TransformPoints()和Graphics.DrawPolygon()。您是否真正能够取得成功还有些疑问,Graphics类不会直接使用GPU加速,因此永远无法与DirectX竞争。