接上篇,绘制着色矩形
C#使用OpenTK绘制一个着色矩形-CSDN博客
上一篇安装OpenTK.GLControl后,这里可以直接拖动控件GLControl
我们会发现GLControl继承于UserControl
//
// 摘要:
// OpenGL-aware WinForms control. The WinForms designer will always call the default
// constructor. Inherit from this class and call one of its specialized constructors
// to enable antialiasing or custom OpenTK.GLControl.GraphicsModes.
public class GLControl : System.Windows.Forms.UserControl
以下我们绘制一个三棱锥,三棱锥需要四个顶点Vertex
新建窗体FormGLControl,拖入一个控件GLControl,绑定Load,Paint等事件
窗体FormGLControl设计器代码为:
文件FormGLControl.Designer.cs
using OpenTK;
namespace OpenTKDemo
{
partial class FormGLControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.glControl1 = new OpenTK.GLControl();
this.SuspendLayout();
//
// glControl1
//
this.glControl1.BackColor = System.Drawing.Color.Black;
this.glControl1.Location = new System.Drawing.Point(12, 12);
this.glControl1.Name = "glControl1";
this.glControl1.Size = new System.Drawing.Size(800, 600);
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.glControl1_MouseDown);
this.glControl1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseMove);
this.glControl1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.glControl1_MouseUp);
this.glControl1.Resize += new System.EventHandler(this.glControl1_Resize);
//
// FormGLControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(832, 619);
this.Controls.Add(this.glControl1);
this.Name = "FormGLControl";
this.Text = "FormGLControl";
this.ResumeLayout(false);
}
#endregion
private GLControl glControl1;
}
}
窗体FormGLControl相关代码如下:
文件FormGLControl.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics.OpenGL;
namespace OpenTKDemo
{
public partial class FormGLControl : Form
{
private int vao, vbo, shaderProgram;
private Matrix4 model, view, projection;
private float rotationX = 0.0f, rotationY = 0.0f; // 旋转角度
private bool isDragging = false;
private Point lastMousePosition;
public FormGLControl()
{
InitializeComponent();
}
private void glControl1_Load(object sender, EventArgs e)
{
// 设置清屏颜色
GL.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// 初始化 VAO 和 VBO
vao = GL.GenVertexArray();
vbo = GL.GenBuffer();
GL.BindVertexArray(vao);
float[] vertices = {
// 顶点位置 // 颜色
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 顶点1(x,y,z,red,green,blue)
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // 顶点2
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, // 顶点3
0.0f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f // 顶点4
};
int[] indices = {
0, 1, 2, // 正面
0, 2, 3, // 右面
0, 3, 1, // 左面
1, 3, 2 // 底面
};
int ebo = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo);
GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(int), indices, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 6 * sizeof(float), 0);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 6 * sizeof(float), 3 * sizeof(float));
GL.EnableVertexAttribArray(1);
// 创建并编译着色器
string vertexShaderSource = @"
#version 330 core
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec3 aColor;
out vec3 vertexColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPosition, 1.0);
vertexColor = aColor;
}
";
string fragmentShaderSource = @"
#version 330 core
in vec3 vertexColor;
out vec4 FragColor;
void main()
{
FragColor = vec4(vertexColor, 1.0);
}
";
int vertexShader = CompileShader(ShaderType.VertexShader, vertexShaderSource);
int fragmentShader = CompileShader(ShaderType.FragmentShader, fragmentShaderSource);
shaderProgram = GL.CreateProgram();
GL.AttachShader(shaderProgram, vertexShader);
GL.AttachShader(shaderProgram, fragmentShader);
GL.LinkProgram(shaderProgram);
// 删除着色器
GL.DeleteShader(vertexShader);
GL.DeleteShader(fragmentShader);
// 初始化矩阵
view = Matrix4.LookAt(new Vector3(0.0f, 0.0f, 2.0f), Vector3.Zero, Vector3.UnitY);
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(45.0f), glControl1.Width / (float)glControl1.Height, 0.1f, 100.0f);
GL.BindVertexArray(0);
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
// 清屏
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
// 绘制三角锥
GL.UseProgram(shaderProgram);
model = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(rotationX)) *
Matrix4.CreateRotationY(MathHelper.DegreesToRadians(rotationY));
GL.UniformMatrix4(GL.GetUniformLocation(shaderProgram, "model"), false, ref model);
GL.UniformMatrix4(GL.GetUniformLocation(shaderProgram, "view"), false, ref view);
GL.UniformMatrix4(GL.GetUniformLocation(shaderProgram, "projection"), false, ref projection);
GL.BindVertexArray(vao);
GL.DrawElements(PrimitiveType.Triangles, 12, DrawElementsType.UnsignedInt, 0);
glControl1.SwapBuffers();
}
private void glControl1_Resize(object sender, EventArgs e)
{
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(45.0f), glControl1.Width / (float)glControl1.Height, 0.1f, 100.0f);
}
private void glControl1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isDragging = true;
lastMousePosition = e.Location;
}
}
private void glControl1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
isDragging = false;
}
}
private void glControl1_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
int deltaX = e.X - lastMousePosition.X;
int deltaY = e.Y - lastMousePosition.Y;
rotationX += deltaY * 0.5f;
rotationY += deltaX * 0.5f;
lastMousePosition = e.Location;
glControl1.Invalidate();
}
}
private int CompileShader(ShaderType type, string source)
{
int shader = GL.CreateShader(type);
GL.ShaderSource(shader, source);
GL.CompileShader(shader);
GL.GetShader(shader, ShaderParameter.CompileStatus, out int status);
if (status == 0)
{
GL.GetShaderInfoLog(shader, out string infoLog);
throw new Exception($"Error compiling shader ({type}): {infoLog}");
}
return shader;
}
}
}