背景:
Silk.GL, 基于Net6.0 跨平台,微软封装的一套三维框架, 总的来说, 参考OpenTK, SharpGL,Vulkan ,DX 等等.
因为基于WPF写的一些demo,每次额外弹出一个黑色窗口来显示内容,不是很爽,那么是否可以将其封装成一个控件,这样就挺方便的吧.
成果展示:
WPF中,在xaml中,引入该控件,
2.显示,完美契合
思路以及用到的知识点:
需要掌握Windows窗口相关的知识,以及窗体变化之后,要捕捉的窗体事件. 因为每次这些窗体变换之后, 需要及时的更新SilkGL的窗口.
关键代码:
1.将链接宿主和GL窗口的信息,抽象封装为一个接口
public interface IHostWindow
{
IntPtr IParentHandle { get; set; } //宿主窗口句柄
IntPtr ICurrentWHandle { get; set; }//当前的窗口句柄
string IWindowTitle { get; set; } //通过Title来获取窗口,进行宿主
void SetRecTangle(int x,int y,int w,int h);
/// <summary>
/// 初始化加载资源
/// </summary>
void InitSource();
/// <summary>
/// 展示窗口.
/// </summary>
void Show();
/// <summary>
/// 关闭的时候,释放一些资源
/// </summary>
void DisposeSource();
Action FinishInitHandle { get; set; }
}
2.基于该接口,实现一个基类 HostBaseUIElement
public class HostBaseUIElement : IHostWindow
{
public HostBaseUIElement()
{
WCount++;
IWindowTitle += $"{WCount}";
}
public IntPtr IParentHandle { get; set; } = IntPtr.Zero;
public IntPtr ICurrentWHandle { get; set; } = IntPtr.Zero;
public string IWindowTitle { get; set; } = "";
public Rectangle BounderBox = new Rectangle(0,0,10,10);
/// <summary>
/// 这里要做的就是,设置Title,ICurrentWHandle,IParentHandle默认不设置
/// </summary>
public static int WCount { get; set; } = 0;
public Action FinishInitHandle { get; set; }
public virtual void SetRecTangle(int x, int y, int w, int h)
{
BounderBox.X = x;
BounderBox.Y = y;
BounderBox.Width = w;
BounderBox.Height = h;
}
public virtual void InitSource()
{
}
public virtual void DisposeSource()
{
}
public virtual void Show()
{
}
}
3.继承并实现自己的 SilkGL 控件,这里呢,我们引入GL控制类
public class SilkGL: HostBaseUIElement
{
public SilkGL() : base() //调用Base来设置初始化.
{
IWindowTitle = $"Silk GL {WCount}";
}
/// <summary>
/// GL窗口
/// </summary>
public IWindow window;
/// <summary>
/// GL对象
/// </summary>
public GL? gl
{
get
{
if (window == null) return null;
return GL.GetApi(window);
}
}
public override void InitSource()
{
var box = BounderBox;
if (box.Width > 0 && box.Height > 0)
{
var options = WindowOptions.Default;
options.Size = new Vector2D<int>(box.Width, box.Height);
options.Title = IWindowTitle;
window = Window.Create(options); //现在想办法,将Window的内容,渲染到UserControl上面去.
window.Title = IWindowTitle;
}
}
public override void Show()
{
window?.Run();
}
public override void DisposeSource()
{
window?.Close();
}
}
4:这里可以进一步封装,,主要完成GL的,本身的一些事件的关联. 然后剩下的就是GL本身的绘制内容了.
5.这里介绍一下使用方式:
5.1,注意我画红线的部分
5.2.后台代码,主要是通过这个SilkwpfName,拿到里面的gl对象,和对应的关键信息
6.0,运行跑起来,就可以很好的做为一个WPF控件来使用了.
一点扩展性和可以做的工作内容
上面控件的设计方式,不单单是可以进行封装SilkGL,还可以封装OSG,VTK,Qt,PLC等等第三方的Windows窗口,只需要继承一下那个HostBaseUIElement 这个基础控件类即可,后续我思考把OSG的也弄一个进来,毕竟OSG的Earth还是蛮有意思的.