You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SharpDX 2D绘图问题求助:椭圆变形、FPS显示异常及代码优化

SharpDX在WinForms中2D绘图问题与优化

一、基础绘图问题(拉伸变形+FPS/GPU显示异常)

问题描述

  1. 调整窗口大小时椭圆出现拉伸变形
  2. FPS与GPU信息无法正常显示
  3. 希望优化现有代码

原代码

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

解决与优化方案

  • 拉伸变形问题:

    1. 窗口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(); // 触发重绘
      }
      
    2. 初始化RenderTarget时指定明确像素格式,替换PixelFormat为:
      PixelFormat = new PixelFormat(Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied)
      
  • 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();
    }
}

解决与优化方案

  • 核心问题:仅初始化时触发一次重绘,后续无持续重绘触发
  • 修改方案:
    1. 设置Timer间隔(如16ms对应约60FPS),在Form1_Load中启动Timer:
      timer1.Interval = 16;
      timer1.Start();
      
    2. 在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();
          }
      }
      
    3. 将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();
      }
      
    4. 在Form的Dispose方法中释放_redBrush与_renderTarget

三、SharpDX 2D C#使用文档咨询

SharpDX官方已停止维护,但仍有实用资源:

  • SharpDX GitHub仓库的Samples目录包含大量2D绘图示例,覆盖基础图形、文本、变换等场景
  • 可参考原生Direct2D官方文档,SharpDX的API与原生Direct2D基本一一对应,可通过原生文档映射理解SharpDX的使用方式
  • 社区整理的SharpDX教程与博客,聚焦WinForms/WPF下的2D绘图实践

内容的提问来源于stack exchange,提问作者Mateusz Antoniak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 12:05:55