简体   繁体   中英

Showing OpenTk.GLControl in winforms

I've been experimenting with showing OpenGl graphics in C# winforms, and I stumbled upon a very useful NuGet package called OpenTK. I followed the introductory tutorial on OpenTK's Learn tab , and was able to render some simple shapes. The tutorial was super helpful, but it is predicated on showing the OpengGL graphics in a GameWindow (separate from the main Form). I found that it is possible to show OpenGL graphics directly in the main Form by using an OpenTK.GLControl control. To make with work, I installed the additional NuGet package OpenTK.GLControl. I added the control in the Form1.Designer.cs file and defined its necessary methods in Form1.cs. However, I'm not able to see the GLControl.

Am I missing a crucial step in my code, or do I have an issue with the packages/dll files?

Form1.Designer.cs:

    private void InitializeComponent()
    {
        /* Generic Form1 code */

        this.gLControl.Location = new System.Drawing.Point(-2, 0);
        this.gLControl.Name = "gLControl";
        this.gLControl.Size = new System.Drawing.Size(500, 300);
        this.gLControl.TabIndex = 0;
        this.gLControl.VSync = false;
        this.gLControl.Load += new System.EventHandler(this.GLControl_Load);
        this.gLControl.Resize += new System.EventHandler(this.GLControl_Resize);
        this.gLControl.Paint += new System.Windows.Forms.PaintEventHandler(this.GLControl_Paint);
    }

    private OpenTK.GLControl gLControl;

Form1.cs:

    private bool _loaded;
    private Shader shader;

    public Form1()
    {
        InitializeComponent();

    }

    private void GLControl_Load(object sender, EventArgs e)
    {
        GL.ClearColor(0.3f, 0.2f, 0.3f, 1.0f);
        GL.Enable(EnableCap.DepthTest);
        GL.Viewport(0, 0, gLControl.Width, gLControl.Height);
        shader = new Shader("shader.vert", "shader.frag");
        shader.Use();
        _loaded = true;
        gLControl.Invalidate();
    }

    private void GLControl_Resize(object sender, EventArgs e)
    {
        if (!_loaded)
            return;
        GL.Viewport(0, 0, gLControl.Width, gLControl.Height);
        gLControl.Invalidate();
    }

    private void GLControl_Paint(object sender, PaintEventArgs e)
    {
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        shader.Use();
        gLControl.SwapBuffers();
    }

Shader.cs:

class Shader
{
    int Handle;

    public Shader(string vertexPath, string fragmentPath)
    {
        int VertexShader;
        int FragmentShader;

        string VertexShaderSource;

        using (StreamReader reader = new StreamReader(vertexPath, Encoding.UTF8))
        {
            VertexShaderSource = reader.ReadToEnd();
        }

        string FragmentShaderSource;

        using (StreamReader reader = new StreamReader(fragmentPath, Encoding.UTF8))
        {
            FragmentShaderSource = reader.ReadToEnd();
        }

        VertexShader = GL.CreateShader(ShaderType.VertexShader);
        GL.ShaderSource(VertexShader, VertexShaderSource);

        FragmentShader = GL.CreateShader(ShaderType.FragmentShader);
        GL.ShaderSource(FragmentShader, FragmentShaderSource);

        GL.CompileShader(VertexShader);

        string infoLogVert = GL.GetShaderInfoLog(VertexShader);
        if (infoLogVert != System.String.Empty)
            Console.WriteLine(infoLogVert);

        GL.CompileShader(FragmentShader);

        string infoLogFrag = GL.GetShaderInfoLog(FragmentShader);

        if (infoLogFrag != System.String.Empty)
            Console.WriteLine(infoLogFrag);

        Handle = GL.CreateProgram();

        GL.AttachShader(Handle, VertexShader);
        GL.AttachShader(Handle, FragmentShader);

        GL.LinkProgram(Handle);

        GL.DetachShader(Handle, VertexShader);
        GL.DetachShader(Handle, FragmentShader);
        GL.DeleteShader(FragmentShader);
        GL.DeleteShader(VertexShader);
    }

    public void Use()
    {
        GL.UseProgram(Handle);
    }

    private bool disposedValue = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            GL.DeleteProgram(Handle);

            disposedValue = true;
        }
    }

    ~Shader()
    {
        GL.DeleteProgram(Handle);
    }


    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

shader.vert:

#version 330 core
layout (location = 0) in vec3 aPosition;

void main()
{
    gl_Position = vec4(aPosition, 1.0);
}

shader.frag:

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

您错过了将控件添加到表单:

this.Controls.Add(this.gLControl);

I am relatively new to c# and an absolute rookie with OpenTK. I spent several weeks digging around the web, attempting to find code that would allow me to work with an OpenTK graphical control inside a WinForm. Below is code that actually works right now, based mostly on the code listed above. This is my way of trying to payback many of the posters on this site.

The other compelling reason for posting this code, is because I have run across many other postings where people say there are very few examples of code for WinForms and OpenTK, and/or examples posted that are many years old (as of 2022).

Form1.Designer.cs :

  private void InitializeComponent()
  {
     this.LblStatus = new System.Windows.Forms.Label();
     this.BtnStart = new System.Windows.Forms.Button();
     this.glControl1 = new OpenTK.GLControl();
     this.SuspendLayout();

Notice the glControl callout above. Note that I did not have make any reference to glControl on Form1 .

In the same file, I had other code regarding glControl . I am assuming that one knows how to add this code to the Designer, as related callouts have to be made to Form1, for the code to work.

     // glControl1
     // 
     this.glControl1.BackColor = System.Drawing.Color.Silver;
     this.glControl1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
     this.glControl1.Location = new System.Drawing.Point(133, 76);
     this.glControl1.Name = "glControl1";
     this.glControl1.Size = new System.Drawing.Size(638, 354);
     this.glControl1.TabIndex = 0;
     this.glControl1.VSync = false;
     this.glControl1.Load += new System.EventHandler(this.glControl1_Load);
     this.glControl1.Paint += new System.Windows.Forms.PaintEventHandler(this.glControl1_Paint);
     this.glControl1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.GLControl_MouseDown);
     this.glControl1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.GLControl_MouseMove);
     this.glControl1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.GLControl_MouseUp);
     this.glControl1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.GLControl_MouseWheel);
     this.glControl1.Resize += new System.EventHandler(this.glControl1_Resize);

Form1 code:

  using System;
  using System.Drawing;
  using System.Windows.Forms;
  using OpenTK.Graphics.OpenGL;

Above are the using statements.

  private void glControl1_Load(object sender, EventArgs e)
  {
     //GL.ClearColor(0.3f, 0.2f, 0.3f, 1.0f);
     //GL.Enable(EnableCap.DepthTest);
     GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
     //shader = new Shader("shader.vert", "shader.frag");
     //shader.Use();
     bLoaded = true;
     GL.ClearColor(Color.SkyBlue);
     glControl1.Invalidate();
  }

Notice that I have commented out some of the above code. That is because I am not interested in shading objects, but instead focusing on 2D graphics.

  private void glControl1_Resize(object sender, EventArgs e)
  {
     if (bLoaded != true)
     {
        return;
     }
     GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
     glControl1.Invalidate();
  }

The Resize code is essentially the same as before.

  private void glControl1_Paint(object sender, PaintEventArgs e)
  {
     GL.Clear(ClearBufferMask.ColorBufferBit | 
     ClearBufferMask.DepthBufferBit);
     //shader.Use();
     glControl1.SwapBuffers();
  }

The Paint code is basically the same, except "shader.Use" is commented out for the same reason as listed above (interested in 2D graphics).

I am positive that there are more experienced programmers here that can make recommended updates to the code listed above. At least this is a starting point for those wanting to get a glControl working on a WinForm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM