Можно ли использовать код OpenGL ES с приложением WPF через D3DImage и ANGLE?

Резюме (версия TL:DR)

В конечном итоге наша цель заключается в том, чтобы иметь возможность использовать код OpenGL ES в приложении WPF изначально (т.е. не SharpGL и т. Д.) И без проблем с воздушным пространством или драйверами, что возможно при использовании проекта Google ANGLE.

Фон:

Одной из вещей, которые мне нравятся в OpenGL поверх DirectX, является его кроссплатформенность. Он имеет отличную поддержку как на OS X и Linux, а также на Android и iOS через ES. Однако в Windows его использование связано с проблемами с драйверами, или, что еще хуже, многие карты просто не реализуют это должным образом.

Войдите в проект Google ANGLE или Почти-Native-Graphics-Layer-Engine.

ANGLE - это оболочка OpenGL ES 2.0 для реализации Direct3D, что означает, что вы можете написать код OpenGL ES 2.0 для запуска в Windows без необходимости использования реальных драйверов OpenGL. Он не только проходит тесты на совместимость с ES, но на самом деле Chrome выполняет всю свою графическую визуализацию, включая WebGL, так что это определенно проверенная технология.

Вопрос:

Мы знаем, что в WPF есть элемент управления D3DImage, который позволяет вам размещать Direct3D-рендеринг в WPF, и он, по-видимому, устраняет проблемы с воздушным пространством, правильно компостируя свой вывод в поток рендеринга WPF. Мой вопрос заключается в том, что ANGLE реализован через Direct3D, а D3DImage является целью для рендеринга Direct3D, возможно ли объединить эти два, что позволяет нам писать код OpenGL ES и размещать его в приложении WPF в Windows, и все это без проблем с драйверами или воздушным пространством?

Это был бы "Святой Грааль" для нас.

Тем не менее, я продолжаю бить стену вокруг получения ANGLE, чтобы нацелить его рендеринг на поверхность D3D, созданную элементом управления D3DImage, поскольку ANGLE хочет использовать свою собственную. Я не уверен, что это даже возможно. Я не могу найти ни одной статьи или ссылки где-либо, кто бы ни обсуждал это, не говоря уже о том, чтобы пытаться это сделать.

И опять же, чтобы быть ясным, цель состоит в том, чтобы заставить наш общий кросс-платформенный код OpenGL (или ES) работать в приложении WPF без проблем воздушного пространства или требований к драйверам OpenGL. Мое предложение использовать ANGLE/D3DImage это просто... попытка. Это "средства", которые я придумала до сих пор, но это лишь потенциальное средство для нашей цели, а не сама цель. Все остальное, что привело бы нас к тому же решению, было бы более чем желанным.

1 ответ

Решение

Я загрузил проект github, который демонстрирует, как интегрировать рендеринг OpenGL в приложение WPF через OpenTK.GLControl.

Код на удивление прост:

  1. Добавить WindowsFormsHost в приложение WPF
  2. Построить OpenTK.GLControl и прикрепить его к WindowsFormsHost
    • Проходить GraphicsContextFlags.Default для настольного OpenGL-контекста
    • Проходить GraphicsContextFlags.Embedded для контекста OpenGL ES (ANGLE)
  3. Визуализация с использованием обычных команд OpenGL или OpenGL ES

Подсказка: OpenTK и OpenTK.GLControl также доступны в виде пакетов NuGet. Завтра выйдет новый релиз с улучшенной поддержкой ANGLE.

Обратите внимание, что подход WindowsFormsHost подчиняется ограничениям воздушного пространства. Если это проблема, см. Мой ответ здесь для решения.

// This code is public domain
#define USE_ANGLE

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using OpenTK;
using OpenTK.Graphics;

#if USE_ANGLE
using OpenTK.Graphics.ES20;
#else
using OpenTK.Graphics.OpenGL;
#endif

namespace WPF.Angle
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        GLControl glControl;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void WindowsFormsHost_Initialized(object sender, EventArgs e)
        {
            var flags = GraphicsContextFlags.Default;
#if USE_ANGLE
            flags = GraphicsContextFlags.Embedded;
#endif
            glControl = new GLControl(new GraphicsMode(32, 24), 2, 0, flags);
            glControl.MakeCurrent();
            glControl.Paint += GLControl_Paint;
            glControl.Dock = DockStyle.Fill;
            (sender as WindowsFormsHost).Child = glControl;
        }

        private void GLControl_Paint(object sender, PaintEventArgs e)
        {
            GL.ClearColor(
                (float)Red.Value,
                (float)Green.Value,
                (float)Blue.Value,
                1);
            GL.Clear(
                ClearBufferMask.ColorBufferBit |
                ClearBufferMask.DepthBufferBit |
                ClearBufferMask.StencilBufferBit);

            glControl.SwapBuffers();
        }

        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            glControl.Invalidate();
        }
    }
}
Другие вопросы по тегам