摘要(TL:DR版本)

最终,我们的目标是能够在WPF应用程序中本机(即非SharpGL等)利用OpenGL ES代码,而不会出现空域或驱动程序问题,这可以使用Google的ANGLE项目来实现。

背景:

我喜欢OpenGL over DirectX的一件事是它的跨平台功能。它在OS X和Linux以及通过ES在Android和iOS上均具有出色的支持。但是,在Windows上,使用它会导致驱动程序问题,或者更糟的是,许多卡根本无法正确实现它。

输入Google的ANGLE project或Almost-Native-Graphics-Layer-Engine。

ANGLE是Direct3D实现的OpenGL ES 2.0包装,这意味着您可以编写要在Windows上运行的OpenGL ES 2.0代码,而无需实际的OpenGL驱动程序。它不仅通过了ES兼容性测试,而且实际上是Chrome进行所有图形渲染(包括WebGL)的方式,因此它绝对是一种可靠的技术。

问题:

我们知道WPF具有D3DImage控件,该控件可让您在WPF中托管Direct3D渲染,并且可以通过将其输出正确堆肥到WPF渲染线程来消除空域问题。我的问题是,由于ANGLE是通过Direct3D实现的,而D3DImage是Direct3D渲染的目标,是否可以将两者结合起来,从而允许我们编写OpenGL ES代码并将其托管在Windows的WPF应用程序中,而没有驱动程序或空间问题?

这将是我们的“圣杯”。

但是,由于ANGLE想要使用自己的渲染,因此我一直在碰壁,使ANGLE将其渲染瞄准由D3DImage控件创建的D3D曲面上。我不确定这是否有可能。我什至在讨论任何内容时都找不到任何文章或参考,更不用说尝试了。

再次明确一点,目标是使我们共享的跨平台OpenGL(或ES)代码在WPF应用程序中运行,而没有空域问题或OpenGL驱动程序要求。我建议使用ANGLE / D3DImage只是一个尝试。到目前为止,这是我想出的“手段”,但这只是实现我们目标的一种潜在手段,而不是目标本身。任何其他使我们能够采用同一解决方案的方法都将受到欢迎。

最佳答案

我上传了一个github project,它演示了如何通过OpenTK.GLControl将OpenGL渲染集成到WPF应用程序中。

代码非常简单:


WindowsFormsHost添加到WPF应用程序
构造一个OpenTK.GLControl并将其附加到WindowsFormsHost


为桌面OpenGL上下文传递GraphicsContextFlags.Default
为OpenGL ES(ANGLE)上下文传递GraphicsContextFlags.Embedded

使用普通的OpenGL或OpenGL ES命令进行渲染


提示:OpenTKOpenTK.GLControl也可以作为NuGet软件包使用。明天将有一个新版本发布,它具有改进的ANGLE支持。

请注意,WindowsFormsHost方法受空域限制。如果这是一个问题,请参见my answer here以获取解决方案。

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

09-10 13:00
查看更多