快速的2D图形WPF [英] Fast 2D graphics in WPF

查看:191
本文介绍了快速的2D图形WPF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要绘制大量的WPF 2D元素,如线条和多边形。他们的立场也需要不断更新。



我已经看过很多,这里的答案使用DrawingVisual或覆盖的OnRender功能,主要是建议的。为了测试这些方法我已经实现了一个简单的粒子系统渲染10000椭圆和我发现,绘图性能使用这两种方法仍然是真正的可怕。在我的电脑我不能让远高于5-10帧每秒。这是完全不能接受的,当你考虑,我很容易地画出流畅使用其他技术的1/2亿粒。



所以我的问题是,我该对运行的技术限制这里WPF还是我失去了一些东西?有没有别的东西,我可以使用?任何建议表示欢迎。



这里的代码我试过



MainWindow.xaml的内容:

 <窗口x:类=WpfApplication1.MainWindow
的xmlns =http://schemas.microsoft.com / WinFX的/ 2006 / XAML /演示
的xmlns:X =http://schemas.microsoft.com/winfx/2006/xaml
标题=主窗口HEIGHT =500WIDTH = 500加载=Window_Loaded>
<电网NAME =xamlGrid>

< /网格和GT;
< /窗GT;



MainWindow.xaml.cs的内容:

 使用System.Windows.Threading程序; 

命名空间WpfApplication1
{
///<总结> $ B $为MainWindow.xaml
///< b ///交互逻辑; /总结>
公共部分类主窗口:窗口
{
公共主窗口()
{
的InitializeComponent();
}


EllipseBounce [] _particles;
DispatcherTimer _timer =新DispatcherTimer();

私人无效Window_Loaded(对象发件人,RoutedEventArgs E)
{

//颗粒椭圆几何
_particles =新EllipseBounce [10000]

//定义区域颗粒可以在
的Rect阶段=反弹围绕新的Rect(0,0,500,500);

//种子随机速度和位置
随机兰特=新的随机()颗粒;

//填充
的for(int i = 0; I< _particles.Length;我++)
{
点POS =新点((浮点)( rand.NextDouble()* stage.Width + stage.X),(浮点)(rand.NextDouble()* stage.Height + stage.Y));
点VEL =新的点((浮点)(rand.NextDouble()* 5 - 2.5),(浮点)(rand.NextDouble()* 5 - 2.5));
_particles [I] =新EllipseBounce(阶段,POS,VEL,2);
}

//添加到粒子系统 - 这将通过的OnRender方法
粒子系统PS =新粒子系统(_particles)绘制颗粒;


//在此元素的网格(假定我们在XAML中的网格名为xmalGrid'
xamlGrid.Children.Add(PS);

//建立和粒子位置
更新功能_timer.Tick + = _timer_Tick;
_timer.Interval =新时间跨度(0,0,0,0 1000/60); /以60 fps
_timer.Start()/更新;

}

无效_timer_Tick(对象发件人,EventArgs五)
{
的for(int i = 0; I< _particles.Length;我++)
{
_particles [I] .Update();
}
}
$} b
$ b ///<总结>
///框架元素,吸引了颗粒
///< /总结>
公共类粒子系统:FrameworkElement的
{
私人DrawingGroup _drawingGroup;

公共粒子系统(EllipseBounce []颗粒)
{
_drawingGroup =新DrawingGroup();

的for(int i = 0; I< particles.Length;我++)
{
EllipseGeometry例如=颗粒[I] .EllipseGeometry;

刷山坳= Brushes.Black;
col.Freeze();

GeometryDrawing GD =新GeometryDrawing(COL,空,例如);

_drawingGroup.Children.Add(GD);
}

}


保护覆盖无效的OnRender(的DrawingContext的DrawingContext)
{
base.OnRender(的DrawingContext);

drawingContext.DrawDrawing(_drawingGroup);
}
}

///<总结>
///简单的类,它实现从墙壁
///<反弹2D粒子运动; /总结>
公共类SimpleBounce2D
{
保护点_position;
保护点_velocity;
保护的矩形_stage;

公共SimpleBounce2D(矩形舞台,点POS机,点VEL)
{
_stage =阶段;

= _position POS;
_velocity =德维尔;
}

公共双X
{
得到
{
返回_position.X;
}
}


公共双Y
{
得到
{
返回_position.Y;
}
}

公共虚拟无效更新()
{
UpdatePosition();
BoundaryCheck();
}

私人无效UpdatePosition()
{
_position.X + = _velocity.X;
_position.Y + = _velocity.Y;
}

私人无效BoundaryCheck()
{
如果(_position.X> _stage.Width + _stage.X)
{
_velocity.X = -_velocity.X;
_position.X = _stage.Width + _stage.X;
}

如果(_position.X< _stage.X)
{
_velocity.X = -_velocity.X;
_position.X = _stage.X;
}

如果(_position.Y> _stage.Height + _stage.Y)
{
_velocity.Y = -_velocity.Y;
_position.Y = _stage.Height + _stage.Y;
}

如果(_position.Y< _stage.Y)
{
_velocity.Y = -_velocity.Y;
_position.Y = _stage.Y;
}
}
}


///<总结>
///延长simplebounce2d加椭圆的几何形状和位置更新的WPF构建
///< /总结>
公共类EllipseBounce:SimpleBounce2D
{
保护EllipseGeometry _ellipse;

公共EllipseBounce(矩形舞台,点POS机,点韦尔,浮动半径)
:基地(台,POS VEL)
{
_ellipse =新EllipseGeometry( POS机,半径,半径);
}

公共EllipseGeometry EllipseGeometry
{
得到
{
返回_ellipse;
}
}

公共覆盖无效更新()
{
base.Update();
_ellipse.Center = _position;
}
}
}


解决方案

我相信提供的示例代码,因为它得到非常好,并展示该框架的限制。在我的测试我异形15-25ms的平均成本是由于渲染开销。从本质上说,我们在这里发言有关中心(dependency-)属性,这是相当昂贵的只是修改。我相信这是昂贵的,因为它传播的变化直接MIL-核心。



一个重要的说明是,间接成本是成正比的对象的位置改变量在模拟。上本身呈现对象的量大不是一个问题,当多数的对象是颞相干即不改变的位置。



对于这种情况的最佳替代方法就是诉诸的 D3DImage 时,这是为Windows Presentation Foundation呈现与DirectX呈现的信息的元素。一般说这种方法应该是有效的,性能明智的。


I need to draw a large amount of 2D elements in WPF, such as lines and polygons. Their position also needs to be updated constantly.

I have looked at many of the answers here which mostly suggested using DrawingVisual or overriding the OnRender function. To test these methods I've implemented a simple particle system rendering 10000 ellipses and I find that the drawing performance is still really terrible using both of these approaches. On my PC I can't get much above 5-10 frames a second. which is totally unacceptable when you consider that I easily draw 1/2 million particles smoothly using other technologies.

So my question is, am I running against a technical limitation here of WPF or am I missing something? Is there something else I can use? any suggestions welcome.

Here the code I tried

content of MainWindow.xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="500" Width="500" Loaded="Window_Loaded">
    <Grid Name="xamlGrid">

    </Grid>
</Window>

content of MainWindow.xaml.cs:

using System.Windows.Threading;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }


        EllipseBounce[]     _particles;
        DispatcherTimer     _timer = new DispatcherTimer();

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

            //particles with Ellipse Geometry
            _particles = new EllipseBounce[10000];

            //define area particles can bounce around in
            Rect stage = new Rect(0, 0, 500, 500);

            //seed particles with random velocity and position
            Random rand = new Random();

            //populate
            for (int i = 0; i < _particles.Length; i++)
            {
               Point pos = new Point((float)(rand.NextDouble() * stage.Width + stage.X), (float)(rand.NextDouble() * stage.Height + stage.Y));
               Point vel = new Point((float)(rand.NextDouble() * 5 - 2.5), (float)(rand.NextDouble() * 5 - 2.5));
                _particles[i] = new EllipseBounce(stage, pos, vel, 2);
            }

            //add to particle system - this will draw particles via onrender method
            ParticleSystem ps = new ParticleSystem(_particles);


            //at this element to the grid (assumes we have a Grid in xaml named 'xmalGrid'
            xamlGrid.Children.Add(ps);

            //set up and update function for the particle position
            _timer.Tick += _timer_Tick;
            _timer.Interval = new TimeSpan(0, 0, 0, 0, 1000 / 60); //update at 60 fps
            _timer.Start();

        }

        void _timer_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < _particles.Length; i++)
            {
                _particles[i].Update();
            }
        }
    }

    /// <summary>
    /// Framework elements that draws particles
    /// </summary>
    public class ParticleSystem : FrameworkElement
    {
        private DrawingGroup _drawingGroup;

        public ParticleSystem(EllipseBounce[] particles)
        {
            _drawingGroup = new DrawingGroup();

            for (int i = 0; i < particles.Length; i++)
            {
                EllipseGeometry eg = particles[i].EllipseGeometry;

                Brush col = Brushes.Black;
                col.Freeze();

                GeometryDrawing gd = new GeometryDrawing(col, null, eg);

                _drawingGroup.Children.Add(gd);
            }

        }


        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);

            drawingContext.DrawDrawing(_drawingGroup);
        }
    }

    /// <summary>
    /// simple class that implements 2d particle movements that bounce from walls
    /// </summary>
    public class SimpleBounce2D
    {
        protected Point     _position;
        protected Point     _velocity;
        protected Rect     _stage;

        public SimpleBounce2D(Rect stage, Point pos,Point vel)
        {
            _stage = stage;

            _position = pos;
            _velocity = vel;
        }

        public double X
        {
            get
            {
                return _position.X;
            }
        }


        public double Y
        {
            get
            {
                return _position.Y;
            }
        }

        public virtual void Update()
        {
            UpdatePosition();
            BoundaryCheck();
        }

        private void UpdatePosition()
        {
            _position.X += _velocity.X;
            _position.Y += _velocity.Y;
        }

        private void BoundaryCheck()
        {
            if (_position.X > _stage.Width + _stage.X)
            {
                _velocity.X = -_velocity.X;
                _position.X = _stage.Width + _stage.X;
            }

            if (_position.X < _stage.X)
            {
                _velocity.X = -_velocity.X;
                _position.X = _stage.X;
            }

            if (_position.Y > _stage.Height + _stage.Y)
            {
                _velocity.Y = -_velocity.Y;
                _position.Y = _stage.Height + _stage.Y;
            }

            if (_position.Y < _stage.Y)
            {
                _velocity.Y = -_velocity.Y;
                _position.Y = _stage.Y;
            }
        }
    }


    /// <summary>
    /// extend simplebounce2d to add ellipse geometry and update position in the WPF construct
    /// </summary>
    public class EllipseBounce : SimpleBounce2D
    {
        protected EllipseGeometry _ellipse;

        public EllipseBounce(Rect stage,Point pos, Point vel, float radius)
            : base(stage, pos, vel)
        {
            _ellipse = new EllipseGeometry(pos, radius, radius);
        }

        public EllipseGeometry EllipseGeometry
        {
            get
            {
                return _ellipse;
            }
        }

        public override void Update()
        {
            base.Update();
            _ellipse.Center = _position;
        }
    }
}

解决方案

I believe the sample code provided is pretty much as good as it gets, and is showcasing the limits of the framework. In my measurements I profiled an average cost of 15-25ms is attributed to render-overhead. In essence we speak here about just the modification of the centre (dependency-) property, which is quite expensive. I presume it is expensive because it propagates the changes to mil-core directly.

One important note is that the overhead cost is proportional to the amount of objects whose position are changed in the simulation. Rendering a large quantity of objects on itself is not an issue when a majority of objects are temporal coherent i.e. don't change positions.

The best alternative approach for this situation is to resort to D3DImage, which is an element for the Windows Presentation Foundation to present information rendered with DirectX. Generally spoken that approach should be effective, performance wise.

这篇关于快速的2D图形WPF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆