Можно ли использовать код 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.
Код на удивление прост:
- Добавить
WindowsFormsHost
в приложение WPF - Построить
OpenTK.GLControl
и прикрепить его кWindowsFormsHost
- Проходить
GraphicsContextFlags.Default
для настольного OpenGL-контекста - Проходить
GraphicsContextFlags.Embedded
для контекста OpenGL ES (ANGLE)
- Проходить
- Визуализация с использованием обычных команд 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();
}
}
}