摘要(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命令进行渲染
提示:OpenTK和OpenTK.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();
}
}
}