当前位置: 首页 > news >正文

图形开发基础之在WinForms中使用OpenTK.GLControl进行图形绘制

在这里插入图片描述

前言

GLControl 是 OpenTK 库中一个重要的控件,专门用于在 Windows Forms 应用程序中集成 OpenGL 图形渲染。通过 GLControl,可以轻松地将 OpenGL 的高性能图形绘制功能嵌入到传统的桌面应用程序中。

1. GLControl 的核心功能

  • OpenGL 渲染上下文: 提供一个 OpenGL 上下文,用于调用 OpenGL 的绘图函数。
  • 与 WinForms 集成: 能嵌入到 WinForms 界面中,与其他控件如按钮、文本框一起使用。
  • 双缓冲支持: 默认启用双缓冲以减少画面撕裂。
  • 硬件加速支持: 自动利用 GPU 的并行计算能力以实现高效渲染。

2. GLControl 的典型使用场景

  1. 实时图形渲染: 游戏开发、3D 数据可视化。
  2. 科学计算可视化: 例如绘制复杂函数曲面、模拟物理系统等。
  3. CAD/建模工具: 提供交互式的 3D 建模功能。
  4. 教学演示: 展示 OpenGL 图形渲染的基本原理和实现方法。

3. GLControl 的主要属性和方法

主要属性

属性描述
Context获取 OpenGL 渲染上下文。
GraphicsMode指定 OpenGL 渲染模式(颜色深度、模板缓冲、抗锯齿等)。
IsIdle指示当前控件是否处于空闲状态,可以用于控制渲染循环。
MakeCurrent()将当前 OpenGL 上下文切换到此控件。
SwapBuffers()交换前缓冲区和后缓冲区,用于实现双缓冲渲染。

主要事件

事件描述
Load在控件加载时触发,用于初始化 OpenGL 配置。
Resize在控件大小调整时触发,用于重新设置视口尺寸。
Paint在控件需要重新绘制时触发,调用 OpenGL 的绘图逻辑。

在这里插入图片描述

4. 使用 GLControl 的完整示例代码

以下代码展示了如何在 Windows Forms 中使用 GLControl 实现鼠标控制旋转的三角锥(四面体)。

环境准备和引用库

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>WinExe</OutputType><TargetFramework>net8.0-windows</TargetFramework><Nullable>enable</Nullable><UseWindowsForms>true</UseWindowsForms><ImplicitUsings>enable</ImplicitUsings></PropertyGroup><ItemGroup><PackageReference Include="OpenTK" Version="5.0.0-pre.13" /><PackageReference Include="OpenTK.Core" Version="5.0.0-pre.13" /><PackageReference Include="OpenTK.Mathematics" Version="5.0.0-pre.13" /><PackageReference Include="OpenTK.GLControl" Version="4.0.1" /><PackageReference Include="OpenTK.Windowing.Common" Version="5.0.0-pre.13" /><PackageReference Include="OpenTK.Windowing.Desktop" Version="5.0.0-pre.13" /></ItemGroup>
</Project>

主窗体代码

using OpenTK.GLControl;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;namespace GLControlExample
{public partial class Form1 : Form{private GLControl glControl;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 Form1(){InitializeComponent();// 创建 GLControlglControl = new GLControl{Dock = DockStyle.Fill};Controls.Add(glControl);// 绑定事件glControl.Load += GlControl_Load;glControl.Paint += GlControl_Paint;glControl.Resize += GlControl_Resize;glControl.MouseDown += GlControl_MouseDown;glControl.MouseUp += GlControl_MouseUp;glControl.MouseMove += GlControl_MouseMove;}private void GlControl_Load(object sender, EventArgs e){// 设置清屏颜色GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 初始化 VAO 和 VBOvao = GL.GenVertexArray();vbo = GL.GenBuffer();GL.BindVertexArray(vao);float[] vertices = {// 顶点位置       // 颜色0.0f,  0.5f,  0.0f,  1.0f, 0.0f, 0.0f, // 顶点1-0.5f, -0.5f,  0.5f,  0.0f, 1.0f, 0.0f, // 顶点20.5f, -0.5f,  0.5f,  0.0f, 0.0f, 1.0f, // 顶点30.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, BufferUsage.StaticDraw);GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo);GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(int), indices, BufferUsage.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 corelayout (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 corein 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), glControl.Width / (float)glControl.Height, 0.1f, 100.0f);GL.BindVertexArray(0);}private void GlControl_Resize(object sender, EventArgs e){GL.Viewport(0, 0, glControl.Width, glControl.Height);projection = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(45.0f), glControl.Width / (float)glControl.Height, 0.1f, 100.0f);}private void GlControl_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.UniformMatrix4f(GL.GetUniformLocation(shaderProgram, "model"),1, false, ref model);GL.UniformMatrix4f(GL.GetUniformLocation(shaderProgram, "view"), 1, false, ref view);GL.UniformMatrix4f(GL.GetUniformLocation(shaderProgram, "projection"), 1, false, ref projection);GL.BindVertexArray(vao);GL.DrawElements(PrimitiveType.Triangles, 12, DrawElementsType.UnsignedInt, 0);glControl.SwapBuffers();}private void GlControl_MouseDown(object sender, MouseEventArgs e){if (e.Button == MouseButtons.Left){isDragging = true;lastMousePosition = e.Location;}}private void GlControl_MouseUp(object sender, MouseEventArgs e){if (e.Button == MouseButtons.Left){isDragging = false;}}private void GlControl_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;glControl.Invalidate();}}private int CompileShader(ShaderType type, string source){int shader = GL.CreateShader(type);GL.ShaderSource(shader, source);GL.CompileShader(shader);GL.GetShaderi(shader, ShaderParameterName.CompileStatus, out int status);if (status == 0){GL.GetShaderInfoLog(shader, out string infoLog);throw new Exception($"Error compiling shader ({type}): {infoLog}");}return shader;}}
}

启动程序

using System;
using System.Windows.Forms;namespace GLControlExample
{static class Program{[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new Form1());}}
}

在这里插入图片描述

5. 性能优势

  • 硬件加速: GLControl 能直接利用 GPU 的并行计算能力,大幅提升复杂场景的渲染效率。
  • 现代 OpenGL 特性: 支持着色器编程、帧缓冲、深度测试等现代图形技术。
  • 与 UI 的无缝集成: 在嵌入 WinForms 界面的同时,保持强大的图形渲染能力。

结语

通过本文,可以了解如何使用 OpenTK.GLControl 进行图形绘制,并掌握GLControl 基本用法,通过硬件加速是实现高效图形渲染。

相关文章:

图形开发基础之在WinForms中使用OpenTK.GLControl进行图形绘制

前言 GLControl 是 OpenTK 库中一个重要的控件&#xff0c;专门用于在 Windows Forms 应用程序中集成 OpenGL 图形渲染。通过 GLControl&#xff0c;可以轻松地将 OpenGL 的高性能图形绘制功能嵌入到传统的桌面应用程序中。 1. GLControl 的核心功能 OpenGL 渲染上下文&…...

离散数学重点复习

第一章.集合论 概念 1.集合是不能精确定义的基本数学概念.通常是由指定范围内的满足给定条件的所有对象聚集在一起构成的 2.制定范围内的每一个对象称为这个集合的元素 3.固定符号如下: N:自然数集合 Z:整数集合 Q:有理数集合 R:实数集合 C:复数集合 4.集合中的元素是…...

Javaweb梳理21——Servlet

Javaweb梳理21——Servlet 21 Servlet21.1 简介21.3 执行流程21.4 生命周期4.5 方法介绍21.6 体系结构21.7 urlPattern配置21.8 XML配置 21 Servlet 21.1 简介 Servlet是JavaWeb最为核心的内容&#xff0c;它是Java提供的一门动态web资源开发技术。使用Servlet就可以实现&…...

推荐学习笔记:矩阵补充和矩阵分解

参考&#xff1a; 召回 fun-rec/docs/ch02/ch2.1/ch2.1.1/mf.md at master datawhalechina/fun-rec GitHub 业务 隐语义模型与矩阵分解 协同过滤算法的特点&#xff1a; 协同过滤算法的特点就是完全没有利用到物品本身或者是用户自身的属性&#xff0c; 仅仅利用了用户与…...

etcd分布式存储系统快速入门指南

在分布式系统的复杂世界中&#xff0c;确保有效的数据管理至关重要。分布式可靠的键值存储在维护跨分布式环境的数据一致性和可伸缩性方面起着关键作用。 在这个全面的教程中&#xff0c;我们将深入研究etcd&#xff0c;这是一个开源的分布式键值存储。我们将探索其基本概念、特…...

解决VUE3 Vite打包后动态图片资源不显示问题

解决VUE3 Vite打包后动态图片资源不显示问题 <script setup> let url ref()const setimg (item)>{let src ../assets/image/${e}.pngurl.value src }</script><template><div v-for"item in 6"><h1 click"setimg(item)"…...

大数据新视界 -- 大数据大厂之 Hive 临时表与视图:灵活数据处理的技巧(上)(29 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

Android学习14--charger

1 概述 最近正好在做关机充电这个&#xff0c;就详细看看吧。还是本着保密的原则&#xff0c;项目里的代码也不能直接用&#xff0c;这里就用的Github的。https://github.com/aosp-mirror 具体位置是&#xff1a;https://github.com/aosp-mirror/platform_system_core/tree/mai…...

页面开发样式和布局入门:Vite + Vue 3 + Less

页面开发样式和布局入门&#xff1a;Vite Vue 3 Less 引言 在现代前端开发中&#xff0c;样式和布局是页面开发的核心部分。随着技术的不断发展&#xff0c;Vite、Vue 3和Less等工具和框架的出现&#xff0c;使得前端开发变得更加高效和灵活。然而&#xff0c;尽管这些工具…...

瑞芯微RK3566/RK3568开发板安卓11固件ROOT教程,Purple Pi OH演示

本文介绍RK3566/RK3568开发板Android11系统&#xff0c;编译ROOT权限固件的方法。触觉智能Purple Pi OH鸿蒙开发板演示&#xff0c;搭载了瑞芯微RK3566四核处理器&#xff0c;Laval鸿蒙社区推荐开发板&#xff0c;已适配全新OpenHarmony5.0 Release系统&#xff0c;SDK源码全开…...

Netty 入门应用:结合 Redis 实现服务器通信

在上篇博客中&#xff0c;我们了解了 Netty 的基本概念和架构。本篇文章将带你深入实践&#xff0c;构建一个简单的 Netty 服务端&#xff0c;并结合 Redis 实现一个数据存取的示例。在这个场景中&#xff0c;Redis 作为缓存存储&#xff0c;Netty 作为服务端处理客户端请求。通…...

试题转excel;pdf转excel;试卷转Excel,word试题转excel

一、问题描述 一名教师朋友&#xff0c;偶尔会需要整理一些高质量的题目到excel中 以往都是手动复制搬运&#xff0c;几百道题几乎需要一个下午的时间 关键这些事&#xff0c;枯燥无聊费眼睛&#xff0c;实在是看起来就很蠢的工作 就想着做一个工具&#xff0c;可以自动处理…...

查看网卡设备Bus号

在Linux系统中&#xff0c;通过ip命令能够看到网卡设备的名称&#xff0c;那么怎么看这个网卡设备对应的硬件设备以及Bus号&#xff1f; 例如在下面的虚拟机中能够看到有一个网口名为enp1s0 如何查看这个设备对应的Bus编号&#xff0c;可以在/sys中找到对应的设备 ll /sys/cl…...

鸿蒙Next星河版高级用例之网络请求和自适应布局以及响应式布局

目录&#xff1a; 1、发起网络请求的两种方式第一种使用httpRequest发送http的请求&#xff1a;1.1、在进行网络请求前&#xff0c;您需要在module.json5文件中申明网络访问权限1.2、GET 请求1.3、POST请求1.4、处理响应的结果第二种使用axios发送http的请求&#xff1a;1.1、在…...

鸿蒙技术分享:敲鸿蒙木鱼,积____功德——鸿蒙元服务开发:从入门到放弃(3)...

本文是系列文章&#xff0c;其他文章见&#xff1a;敲鸿蒙木鱼&#xff0c;积____功德&#x1f436;&#x1f436;&#x1f436;——鸿蒙元服务开发&#xff1a;从入门到放弃(1)敲鸿蒙木鱼&#xff0c;积____功德&#x1f436;&#x1f436;&#x1f436;——鸿蒙元服务开发&am…...

Hadoop生态圈框架部署 伪集群版(六)- MySQL安装配置

文章目录 前言一、MySQL安装与配置1. 安装MySQL2. 安装MySQL服务器3. 启动MySQL服务并设置开机自启动4. 修改MySQL初始密码登录5. 设置允许MySQL远程登录6. 登录MySQL 卸载1. 停止MySQL服务2. 卸载MySQL软件包3. 删除MySQL配置文件及数据目录 前言 在本文中&#xff0c;我们将…...

【Docker】创建Docker并部署Web站点

要在服务器上创建Docker容器&#xff0c;并在其中部署站点&#xff0c;你可以按照以下步骤操作。我们将以Flask应用为例来说明如何完成这一过程。 1. 准备工作 确保你的服务器已经安装了Docker。如果没有&#xff0c;请根据官方文档安装&#xff1a; Docker 安装指南 2. 创…...

实验七 用 MATLAB 设计 FIR 数字滤波器

实验目的 加深对窗函数法设计 FIR 数字滤波器的基本原理的理解。 学习用 Matlab 语言的窗函数法编写设计 FIR 数字滤波器的程序。 了解 Matlab 语言有关窗函数法设计 FIR 数字滤波器的常用函数用法。 掌握 FIR 滤波器的快速卷积实现原理。 不同滤波器的设计方法具有不同的优…...

学习ESP32开发板安装鸿蒙操作系统(新板子esp32c3不支持)

鸿蒙LiteOS网址&#xff1a;LiteOS: Huawei LiteOS开源代码官方主仓库.LiteOS Studio 开发工具请访问https://gitee.com/LiteOS/LiteOS_Studio 失败的实践记录见&#xff1a;完全按照手册win10里装Ubuntu 虚拟机然后编译ESP32&#xff08;主要是想针对ESP32C3和S3&#xff09;…...

asp.net core过滤器应用

筛选器类型 授权筛选器 授权过滤器是过滤器管道的第一个被执行的过滤器&#xff0c;用于系统授权。一般不会编写自定义的授权过滤器&#xff0c;而是配置授权策略或编写自定义授权策略。简单举个例子。 using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCo…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...

[USACO23FEB] Bakery S

题目描述 Bessie 开了一家面包店! 在她的面包店里&#xff0c;Bessie 有一个烤箱&#xff0c;可以在 t C t_C tC​ 的时间内生产一块饼干或在 t M t_M tM​ 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC​,tM​≤109)。由于空间…...

鸿蒙Navigation路由导航-基本使用介绍

1. Navigation介绍 Navigation组件是路由导航的根视图容器&#xff0c;一般作为Page页面的根容器使用&#xff0c;其内部默认包含了标题栏、内容区和工具栏&#xff0c;其中内容区默认首页显示导航内容&#xff08;Navigation的子组件&#xff09;或非首页显示&#xff08;Nav…...