gpt4 book ai didi

c# - WPF 中的快速二维图形

转载 作者:IT王子 更新时间:2023-10-29 04:05:14 25 4
gpt4 key购买 nike

我需要在 WPF 中绘制大量的二维元素,例如直线和多边形。他们的位置也需要不断更新。

我看过这里的许多答案,其中大部分建议使用 DrawingVisual 或重写 OnRender 函数。为了测试这些方法,我实现了一个简单的粒子系统渲染 10000 个椭圆,我发现使用这两种方法的绘图性能仍然非常糟糕。在我的电脑上,我每秒不能超过 5-10 帧。当你认为我使用其他技术轻松平滑地绘制 1/2 百万个粒子时,这是完全不能接受的。

所以我的问题是,我是否遇到了 WPF 的技术限制,或者我是否遗漏了什么?还有什么我可以用的吗?欢迎任何建议。

这里是我试过的代码

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>

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;
}
}
}

最佳答案

我相信所提供的示例代码已经很不错了,并且展示了框架的局限性。在我的测量中,我分析了 15-25 毫秒的平均成本归因于渲染开销。本质上,我们在这里谈论的只是中心(依赖)属性的修改,这是非常昂贵的。我认为它很昂贵,因为它会将更改直接传播到 mil-core。

一个重要的注意事项是,开销成本与模拟中位置发生变化的对象数量成正比。当大多数对象在时间上是一致的,即不改变位置时,在自身上渲染大量对象不是问题。

对于这种情况,最好的替代方法是求助于 D3DImage ,这是 Windows Presentation Foundation 的一个元素,用于呈现使用 DirectX 呈现的信息。一般来说,这种方法应该是有效的,性能明智的。

关于c# - WPF 中的快速二维图形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16107877/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com