Silk.Net Opengl 创建基于WPF或者Winform 的显示控件

本文介绍了如何将Silk.GL框架封装为一个WPF控件,以避免每次额外弹出窗口。通过创建一个接口IHostWindow和基类HostBaseUIElement,实现了窗口信息的管理,并在SilkGL控件中集成GL渲染。这种方法不仅适用于Silk.GL,还可用于封装其他第三方窗口,如OSG、VTK等。通过后台代码获取控件内的GL对象,可以方便地在WPF应用中使用和操作3D图形。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:

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还是蛮有意思的.

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值