SharpDX 2D绘图问题求助:椭圆变形、FPS显示异常及代码优化
一、基础绘图问题(拉伸变形+FPS/GPU显示异常)
问题描述
- 调整窗口大小时椭圆出现拉伸变形
- FPS与GPU信息无法正常显示
- 希望优化现有代码
原代码
private WindowRenderTarget _renderTarget; private Ellipse el; private Stopwatch _stopwatch = new Stopwatch(); private int _frameCount; private string _gpuDescription; public Form1() { InitializeComponent(); InitializeDirect2D(); el = new Ellipse { RadiusX = 50, RadiusY = 50, Point = new RawVector2(ClientSize.Width / 2.0f, ClientSize.Height / 2.0f) }; using (var factory = new SharpDX.DXGI.Factory1()) { using (var adapter = factory.GetAdapter1(0)) { _gpuDescription = adapter.Description.Description; } } this.Text = _gpuDescription; } private void InitializeDirect2D() { var dpi = this.CreateGraphics().DpiX; var properties = new HwndRenderTargetProperties { Hwnd = this.Handle, PixelSize = new Size2(this.ClientSize.Width, this.ClientSize.Height), PresentOptions = PresentOptions.None }; var renderTargetProperties = new RenderTargetProperties { DpiX = dpi, DpiY = dpi, Type = RenderTargetType.Hardware, Usage = RenderTargetUsage.GdiCompatible, PixelFormat = new PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied) }; _renderTarget = new WindowRenderTarget(new SharpDX.Direct2D1.Factory(), renderTargetProperties, properties); } private void Form1_Load(object sender, EventArgs e) { timer1.Start(); } private void Form1_Paint(object sender, PaintEventArgs e) { SolidColorBrush brush = new SolidColorBrush(_renderTarget, new RawColor4(1.0f, 0.0f, 0.0f, 1.0f)); _renderTarget.BeginDraw(); _renderTarget.Clear(new RawColor4(0, 0, 0, 1)); _renderTarget.FillEllipse(el, brush); _renderTarget.EndDraw(); } private void Form1_Resize(object sender, EventArgs e) { } private void timer1_Tick(object sender, EventArgs e) { _frameCount++; if (_stopwatch.ElapsedMilliseconds >= 1000) { this.Text = $"FPS: {_frameCount}, GPU: {_gpuDescription}"; _frameCount = 0; _stopwatch.Restart(); } }
解决与优化方案
拉伸变形问题:
- 窗口Resize时未更新RenderTarget尺寸与椭圆位置,在
Form1_Resize中添加:if (_renderTarget != null) { _renderTarget.Resize(new Size2(ClientSize.Width, ClientSize.Height)); el.Point = new RawVector2(ClientSize.Width / 2.0f, ClientSize.Height / 2.0f); Invalidate(); // 触发重绘 } - 初始化RenderTarget时指定明确像素格式,替换
PixelFormat为:PixelFormat = new PixelFormat(Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied)
- 窗口Resize时未更新RenderTarget尺寸与椭圆位置,在
FPS/GPU显示异常:
在Form1_Load中启动Stopwatch:_stopwatch.Start();代码优化:
- 将
SolidColorBrush设为类成员,初始化时创建、Dispose时释放,避免每次Paint重复创建 - 在Form的Dispose方法中添加SharpDX资源释放逻辑,防止内存泄漏
- 将
二、椭圆移动不显示问题
问题描述
更新椭圆坐标后,椭圆未呈现移动效果
原代码
private WindowRenderTarget _renderTarget; private Ellipse el; private Stopwatch _stopwatch = new Stopwatch(); private int _frameCount; private string _gpuDescription; private float ellipseXPosition = 100; // Starting x-coordinate private const float MovementSpeed = 2f; public Form1() { InitializeComponent(); InitializeDirect2D(); el = new Ellipse { RadiusX = 50, RadiusY = 50, Point = new RawVector2(100, 100) }; using (var factory = new SharpDX.DXGI.Factory1()) { using (var adapter = factory.GetAdapter1(0)) { _gpuDescription = adapter.Description.Description; } } _stopwatch.Start(); // Force a repaint this.Invalidate(); } private void InitializeDirect2D() { var dpi = this.CreateGraphics().DpiX; var properties = new HwndRenderTargetProperties { Hwnd = this.Handle, PixelSize = new Size2(this.ClientSize.Width, this.ClientSize.Height), PresentOptions = PresentOptions.None }; var renderTargetProperties = new RenderTargetProperties { DpiX = dpi, DpiY = dpi, Type = RenderTargetType.Hardware, Usage = RenderTargetUsage.GdiCompatible, PixelFormat = new PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied) }; _renderTarget = new WindowRenderTarget(new SharpDX.Direct2D1.Factory(), renderTargetProperties, properties); } private void Form1_Load(object sender, EventArgs e) { } private void Form1_Paint(object sender, PaintEventArgs e) { Console.WriteLine("Form1_Paint method called"); SolidColorBrush brush = new SolidColorBrush(_renderTarget, new RawColor4(1.0f, 0.0f, 0.0f, 1.0f)); _renderTarget.BeginDraw(); _renderTarget.Clear(new RawColor4(0, 0, 0, 1)); // Update the position of the ellipse el.Point = new RawVector2(ellipseXPosition, 100); // Y-coordinate remains the same // Rysowanie elipsy _renderTarget.FillEllipse(el, brush); _renderTarget.EndDraw(); // Move the ellipse to the right for the next frame ellipseXPosition += MovementSpeed; // Check if the ellipse reaches the right boundary and reset its position if (ellipseXPosition > this.ClientSize.Width) { ellipseXPosition = -el.RadiusX; // Reset to the left side of the window } } private void Form1_Resize(object sender, EventArgs e) { if (_renderTarget != null) { _renderTarget.Resize(new Size2(ClientSize.Width, ClientSize.Height)); } } private void timer1_Tick(object sender, EventArgs e) { _frameCount++; if (_stopwatch.ElapsedMilliseconds >= 1000) { this.Text = $"FPS: {_frameCount}, GPU: {_gpuDescription}"; _frameCount = 0; _stopwatch.Restart(); } }
解决与优化方案
- 核心问题:仅初始化时触发一次重绘,后续无持续重绘触发
- 修改方案:
- 设置Timer间隔(如16ms对应约60FPS),在
Form1_Load中启动Timer:timer1.Interval = 16; timer1.Start(); - 在
timer1_Tick中更新位置并触发重绘:private void timer1_Tick(object sender, EventArgs e) { ellipseXPosition += MovementSpeed; if (ellipseXPosition > this.ClientSize.Width) { ellipseXPosition = -el.RadiusX; } Invalidate(); // FPS统计逻辑保留 _frameCount++; if (_stopwatch.ElapsedMilliseconds >= 1000) { this.Text = $"FPS: {_frameCount}, GPU: {_gpuDescription}"; _frameCount = 0; _stopwatch.Restart(); } } - 将
SolidColorBrush设为类成员重用,Paint方法简化为:private SolidColorBrush _redBrush; // 构造函数中初始化 _redBrush = new SolidColorBrush(_renderTarget, new RawColor4(1.0f, 0.0f, 0.0f, 1.0f)); private void Form1_Paint(object sender, PaintEventArgs e) { _renderTarget.BeginDraw(); _renderTarget.Clear(new RawColor4(0, 0, 0, 1)); el.Point = new RawVector2(ellipseXPosition, 100); _renderTarget.FillEllipse(el, _redBrush); _renderTarget.EndDraw(); } - 在Form的Dispose方法中释放
_redBrush与_renderTarget
- 设置Timer间隔(如16ms对应约60FPS),在
三、SharpDX 2D C#使用文档咨询
SharpDX官方已停止维护,但仍有实用资源:
- SharpDX GitHub仓库的Samples目录包含大量2D绘图示例,覆盖基础图形、文本、变换等场景
- 可参考原生Direct2D官方文档,SharpDX的API与原生Direct2D基本一一对应,可通过原生文档映射理解SharpDX的使用方式
- 社区整理的SharpDX教程与博客,聚焦WinForms/WPF下的2D绘图实践
内容的提问来源于stack exchange,提问作者Mateusz Antoniak
相关产品推荐
相关产品推荐

