Рисование 3D-моделей WPF в реальном времени

В моей программе управления роботом должна быть 3D-модель робота, движущегося одновременно с реальным роботом. Я загрузил 3D-модель и обновил ее положение, отпустив ползунок с помощью мыши. Все работает, но при обновлении модели в реальном времени все приложение зависает.

Как рисовать новую модель робота каждые 0,1 секунды, чтобы рисование не тормозило отображение другой информации на экране и не мешало нажатию клавиш?

Thread ThreadUpdateRobot = new Thread(new ThreadStart(OnPointAsync));
ThreadUpdateRobot.Start();
public void OnPoint()
{
    Dispatcher.Invoke(() => UpdateObjectZveno(angleFor3D));
    Dispatcher.Invoke(() => pictureBox.Paint += new System.Windows.Forms.PaintEventHandler(OnPaint));
    Dispatcher.Invoke(() => pictureBox.Invalidate());
}

private void OnPaint(object sender, System.Windows.Forms.PaintEventArgs e)
{
    for (int i = 0; i < device.Segments.Count; i++)
        DrawSegment(e.Graphics, device.Segments[i], colors[i % colors.Length], false);
}
private void DrawSegment(Graphics gr, Segment segment, System.Drawing.Color color, bool debugMode)
{
    var model = segment.VisualMesh;
    var scaleM = Matrix4x4.CreateScale(scale / 2);               //scale matrix
    var translateM = Matrix4x4.CreateTranslation(position);      //offset matrix
    var paneXY = new Matrix4x4() { M11 = 1f, M22 = 1f, M44 = 1f }; //projection matrix

    var m = scaleM * translateM * paneXY; //total matrix
    var vertices = model.Vertexes;

    if (debugMode)
    {
        vertices.Clear();
        vertices.Add(segment.Start);
        vertices.Add(segment.End);
    }

    //translate to world
    vertices = segment.ToWorld(vertices);

    //apply scale, offset and projection
    vertices = vertices.Select(v => Vector3.Transform(v, m)).ToList();

    if (debugMode)
    {
        var p1 = new PointF(vertices[0].X, vertices[0].Y);
        var p2 = new PointF(vertices[1].X, vertices[1].Y);

        using (var pen = new System.Drawing.Pen(color, 2))
            gr.DrawLine(pen, p1, p2);
        gr.DrawEllipse(Pens.Blue, p1.X - 3, p1.Y - 3, 6, 6);
        gr.DrawEllipse(Pens.Blue, p2.X - 3, p2.Y - 3, 6, 6);

        return;
    }

    //create graphicsPath
    using (var path = new GraphicsPath())
    {
        //create faces
        var prev = Vector3.Zero;
        var prevF = 0;
        foreach (var f in model.Fig)
        {
            if (f == 0) path.CloseFigure();
            var v = vertices[f];
            if (prevF != 0 && f != 0)
                path.AddLine(prev.X, prev.Y, v.X, v.Y);
            prev = v;
            prevF = f;
        }
        using (var pen = new System.Drawing.Pen(color))
            gr.DrawPath(pen, path);
    }
}
public MainWindow()
{
    System.Windows.Forms.Integration.WindowsFormsHost host = new System.Windows.Forms.Integration.WindowsFormsHost();
    pictureBox = new System.Windows.Forms.PictureBox
    {

        Anchor = System.Windows.Forms.AnchorStyles.Top,
        BackColor = System.Drawing.Color.White
    };
    pictureBox.Paint += new System.Windows.Forms.PaintEventHandler(OnPaint);
    windowsFormsHost1.Child = pictureBox;


    UpdateObjectBase();

    pictureBox.Paint += new System.Windows.Forms.PaintEventHandler(OnPaint);
}

XAML

<WindowsFormsHost Height="254" HorizontalAlignment="Left" Margin="714,339,0,0" Name="windowsFormsHost1" VerticalAlignment="Top" Width="467" Grid.Column="1" Grid.ColumnSpan="2" />

person Vita Robertov    schedule 18.12.2019    source источник
comment
Вы уже используете GDI+, что является хорошей идеей для ускорения рисования. Но, пожалуйста, не используйте pictureBox из winforms для его отображения. Вы можете рисовать в растровое изображение, а затем создавать его копию и вызывать для ее отображения внутри wpf Изображение.   -  person Sinatr    schedule 18.12.2019
comment
Да, я знаю, что pictureBox плохой метод, но моих знаний не хватает, чтобы перенести это в wpf   -  person Vita Robertov    schedule 18.12.2019
comment
Что именно вы не знаете? В настоящее время вы используете дескриптор события Graphics из Paint. Вместо этого создайте собственный поток для цикла рисования, создайте там графику из растрового изображения, нарисуйте, как вы это делаете, затем преобразуйте изображение в BitmapSource и установите для него Image.Source (не забудьте использовать Dispatcher.Invoke), повторите. Вот фрагмент, который заботится о нехватке памяти.   -  person Sinatr    schedule 18.12.2019