OpenTK为SkiaSharp在.NET 环境下提供OpenGL支持,使其进行高效的2D渲染

在这里插入图片描述

前言

在 .NET 环境下,OpenTK 为 SkiaSharp 提供了 OpenGL 支持,使得 SkiaSharp 能够利用 OpenGL 进行高效的 2D 渲染。这种结合能够充分发挥 GPU 的加速能力,从而提升渲染性能,尤其是在需要进行复杂图形处理或频繁更新的应用中,如游戏开发、图形编辑器或实时数据可视化等场景。本文将详细介绍两者的关系、使用场景,以及如何通过示例代码将它们集成到一个项目中。

一、SkiaSharp 简介

1. 什么是 SkiaSharp?

在这里插入图片描述
SkiaSharp 是 Google Skia 图形引擎的 .NET 封装,提供了一套跨平台、高效的 2D 图形绘制 API。
它的主要特点包括:

  • 强大的 2D 绘图功能:绘制文本、矢量图形、图像等。
  • 跨平台支持:兼容 Windows、Linux、macOS、iOS 和 Android。
  • 抽象底层细节:支持多种后端(OpenGL、Direct3D、Metal、Vulkan 等),对开发者透明。
  • 易于使用:以简单的 C# API 实现复杂的图形绘制。

2. SkiaSharp 的应用场景

  • 绘制跨平台的 2D 界面(如图表、控件)。
  • 实现自定义图形效果(如矢量动画)。
  • 构建高性能的 UI 组件。

二、OpenTK 简介

1. 什么是 OpenTK?

在这里插入图片描述

OpenTK(Open Toolkit) 是一个专为 .NET 开发的开源框架,封装了 OpenGL(图形)、OpenGL ES(嵌入式图形)和 OpenAL(音频) 的功能。
它允许开发者直接使用底层 GPU 功能,实现高性能的 3D 渲染和多媒体处理。

2. OpenTK 的主要特点

  • 灵活性高:直接控制 OpenGL 渲染管线,包括顶点、片段着色器等。
  • 适用于高性能需求:例如游戏开发、3D 可视化。
  • 跨平台支持:兼容主流桌面平台(Windows、Linux、macOS)。

3. OpenTK 的应用场景

  • 构建游戏引擎或 3D 编辑器。
  • 实现复杂的实时 3D 渲染效果。
  • 使用 OpenGL 直接控制 GPU。

三、SkiaSharp 和 OpenTK 的关系

在这里插入图片描述
虽然 SkiaSharp 和 OpenTK 是两个独立的库,但它们可以协同工作。SkiaSharp 的某些后端渲染(如 SKGLControl )依赖 OpenGL,这为它们的结合提供了可能性。以下是两者关系的几个关键点:

1. SkiaSharp 的 OpenGL 后端

SkiaSharp 提供了 OpenGL 支持,用于提高绘图效率:

  • 在桌面端,SkiaSharp 使用 OpenGL 渲染 2D 图形(通过 SKGLControl)。
  • OpenTK 是 OpenGL 在 .NET 环境下的一种实现,因此可以作为 SkiaSharp 的底层支持。

2. 互补的特性

特性SkiaSharpOpenTK
2D 图形绘制高效、简单,功能强大可实现,但代码复杂
3D 渲染支持不支持原生支持,灵活高效
底层控制能力屏蔽底层实现,抽象度高完全暴露 OpenGL API
开发难度易于上手需要熟悉 OpenGL 概念

两者的特性互补,使得在一些场景中,开发者可以结合它们实现 2D 和 3D 图形的混合渲染。

四、SkiaSharp 和 OpenTK 的结合使用

1. 使用场景

  • 2D 和 3D 混合渲染:使用 OpenTK 渲染 3D 图形,并用 SkiaSharp 绘制叠加的 2D 图形。
  • 共享 OpenGL 上下文:OpenTK 的 OpenGL 上下文可以传递给 SkiaSharp,利用 SkiaSharp 的高层 API 进行 2D 绘图。

2. 示例:SkiaSharp + OpenTK 动态绘制波形

以下示例演示如何通过 OpenTK 创建 OpenGL 上下文,并使用 SkiaSharp 绘制动态波形。

1. 环境依赖
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>WinExe</OutputType><TargetFramework>net8.0-windows10.0.19041.0</TargetFramework><Nullable>disable</Nullable><UseWindowsForms>true</UseWindowsForms><ImplicitUsings>enable</ImplicitUsings></PropertyGroup><ItemGroup>                                          <PackageReference Include="SkiaSharp" Version="3.118.0-preview.1.2" /><PackageReference Include="SkiaSharp.Views.WindowsForms" Version="3.118.0-preview.1.2" /></ItemGroup>
</Project>

在这里插入图片描述

2. 编写代码

构建SkiaOpenGLControl,继承GLControl

using OpenTK.GLControl;
using OpenTK.Graphics.OpenGL;
using SkiaSharp;public class SkiaOpenGLControl : GLControl
{private GRContext _grContext;                      // SkiaSharp 上下文private GRBackendRenderTarget _renderTarget;       // Skia 渲染目标private SKSurface _skSurface;                      // Skia 表面private bool _initialized = false;                 // 控件是否已初始化private readonly object _lock = new object();      // 锁对象,确保线程安全public SkiaOpenGLControl(): base(GLControlSettings.Default){Initialize();}private void Initialize(){if (_initialized) return;MakeCurrent(); // 绑定 OpenGL 上下文var glInterface = GRGlInterface.Create();_grContext = GRContext.CreateGl(glInterface);CreateSkiaSurface();_initialized = true;}private void CreateSkiaSurface(){_skSurface?.Dispose();_renderTarget?.Dispose();int width = Width;int height = Height;GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);var framebufferInfo = new GRGlFramebufferInfo(0, (uint)All.Rgba8);_renderTarget = new GRBackendRenderTarget(width, height, 0, 8, framebufferInfo);_skSurface = SKSurface.Create(_grContext, _renderTarget, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888);}public void RenderOnUIThread(Action<SKCanvas> drawAction){lock (_lock){MakeCurrent();var canvas = _skSurface.Canvas;canvas.Clear(SKColors.White);drawAction(canvas);canvas.Flush();SwapBuffers();}}protected override void OnResize(EventArgs e){base.OnResize(e);if (_initialized){MakeCurrent();CreateSkiaSurface();}}protected override void Dispose(bool disposing){if (disposing){_skSurface?.Dispose();_renderTarget?.Dispose();_grContext?.Dispose();}base.Dispose(disposing);}
}

构建绘图数据队列+定时生成绘图数据,触发UI刷新

using SkiaSharp;
namespace GLControlExample
{public partial class Form2 : Form{private readonly SkiaOpenGLControl _skiaControl;private Thread _drawThread;private bool _isRunning;private readonly Queue<List<SKPoint>> _waveDataQueue = new(); // 绘图数据队列private readonly object _queueLock = new();                  // 队列锁private float _time;public Form2(){InitializeComponent();_skiaControl = new SkiaOpenGLControl { Dock = DockStyle.Fill };Controls.Add(_skiaControl);}private void Form2_Load(object sender, EventArgs e){_isRunning = true;_drawThread = new Thread(GenerateWaveData){IsBackground = true};_drawThread.Start();// UI 定时绘图var timer = new System.Windows.Forms.Timer { Interval = 16 };timer.Tick += (s, args) =>{List<SKPoint> waveData;lock (_queueLock){if (_waveDataQueue.Count == 0) return;waveData = _waveDataQueue.Dequeue();}// 在 UI 线程中绘图_skiaControl.RenderOnUIThread(canvas =>{DrawWave(canvas, waveData);});};timer.Start();}private void GenerateWaveData(){while (_isRunning){var width = _skiaControl.Width;var height = _skiaControl.Height;var points = new List<SKPoint>();for (int i = 0; i < width; i += 5){float x = i;float y = (float)(height / 2 + Math.Sin((_time + i) * 0.05) * 50);points.Add(new SKPoint(x, y));}lock (_queueLock){_waveDataQueue.Enqueue(points);if (_waveDataQueue.Count > 10) _waveDataQueue.Dequeue(); // 控制队列长度}_time += 0.5f;Thread.Sleep(16); // 控制生成频率}}private void DrawWave(SKCanvas canvas, List<SKPoint> points){using var paint = new SKPaint{Color = SKColors.Blue,StrokeWidth = 2,IsAntialias = true};canvas.DrawPoints(SKPointMode.Polygon, points.ToArray(), paint);}protected override void OnFormClosing(FormClosingEventArgs e){_isRunning = false;_drawThread.Join();base.OnFormClosing(e);}}
}
3. 运行程序

在这里插入图片描述

五、总结

1. 适用场景

  • SkiaSharp 适合需要高效 2D 绘图的应用场景,例如绘制图表、界面或文本。
  • OpenTK 则是实现高性能 3D 渲染和复杂图形处理的理想工具。

2. 结合优势

通过结合 SkiaSharp 和 OpenTK,开发者可以在 OpenGL 提供的灵活环境中,轻松实现 2D 和 3D 图形的混合渲染。

3. 实践建议

  • 如果项目主要是 2D 绘图,优先使用 SkiaSharp。
  • 如果需要 3D 渲染或底层控制,考虑直接使用 OpenTK。

SkiaSharp 和 OpenTK 是两个互补的工具,灵活搭配使用可以大大提升开发效率和图形效果的表现力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/63271.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux-FrameBuffer设备(LCD)应用编程

本章学习 Linux 下的 Framebuffer 应用编程&#xff0c;通过对本章内容的学习&#xff0c;大家将会了解到 Framebuffer 设备究竟是什么&#xff1f;以及如何编写应用程序来操控 FrameBuffer 设备。 本章将会讨论如下主题。 ⚫ 什么是 Framebuffer 设备&#xff1f; ⚫ LCD 显示…

IDEA中MAVEN的一些设置问题

关于IDEA中MAVEN的一些设置问题 这三个配置的作业分别是什么呢&#xff1f; 在这张截图中&#xff0c;Maven的三个设置分别是&#xff1a; Maven home path (Maven主目录路径)&#xff1a; 这是Maven的安装路径&#xff0c;指向Maven的主目录。通常包含 bin、conf 等文件夹。用…

HBU深度学习实验14.5-循环神经网络(1.5)

梯度爆炸实验 造成简单循环网络较难建模长程依赖问题的原因有两个&#xff1a;梯度爆炸和梯度消失。一般来讲&#xff0c;循环网络的梯度爆炸问题比较容易解决&#xff0c;一般通过权重衰减或梯度截断可以较好地来避免&#xff1b;对于梯度消失问题&#xff0c;更加有效的方式…

Leetcode经典题4--查找数组中的多数元素+Boyer-Moore 投票算法

题目描述&#xff1a; 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。 输入输出示例 输入&#xff1a;nums [2,2,1,1,1,2,2] 输出…

android studio 读写文件操作(应用场景二)

android studio版本&#xff1a;2023.3.1 patch2 例程&#xff1a;readtextviewIDsaveandread 本例程是个过渡例程&#xff0c;如果单是实现下图的目的有更简单的方法&#xff0c;但这个方法是下一步工作的基础&#xff0c;所以一定要做。 例程功能&#xff1a;将两个textvi…

【NLP 9、实践 ① 五维随机向量交叉熵多分类】

目录 五维向量交叉熵多分类 规律&#xff1a; 实现&#xff1a; 1.设计模型 2.生成数据集 3.模型测试 4.模型训练 5.对训练的模型进行验证 调用模型 你的平静&#xff0c;是你最强的力量 —— 24.12.6 五维向量交叉熵多分类 规律&#xff1a; x是一个五维(索引)向量&#xff…

windows文件下换行, linux上不换行 解决CR换行符替换为LF notepad++

html文件是用回车换行的&#xff0c;在windows电脑上&#xff0c;显示正常。 文件上传到linux服务器后&#xff0c;文件不换行了。只有一行。而且相关js插件也没法正常运行。 用notepad查看&#xff0c;显示尾部换行符&#xff0c;是CR&#xff0c;这就是原因。CR是不被识别的。…

Unity 模拟百度地图,使用鼠标控制图片在固定区域内放大、缩小、鼠标左键拖拽移动图片

效果展示&#xff1a; 步骤流程&#xff1a; 1.使用的是UGUI&#xff0c;将下面的脚本拖拽到图片上即可。 using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems;public class CheckImage : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragH…

游戏引擎学习第30天

仓库: https://gitee.com/mrxiao_com/2d_game 回顾 在这段讨论中&#xff0c;重点是对开发过程中出现的游戏代码进行梳理和进一步优化的过程。 工作回顾&#xff1a;在第30天&#xff0c;回顾了前一天的工作&#xff0c;并提到今天的任务是继续从第29天的代码开始&#xff0c…

基于MFC绘制门电路

MFC绘制门电路 1. 设计内容、方法与难点 本课题设计的内容包括了基本门电路中与门和非门的绘制、选中以及它们之间的连接。具体采用的方法是在OnDraw函数里面进行绘制&#xff0c;并设计元器件基类&#xff0c;派生出与门和非门&#xff0c;并组合了一个引脚类&#xff0c;在…

【text2sql】低资源场景下Text2SQL方法

SFT使模型能够遵循输入指令并根据预定义模板进行思考和响应。如上图&#xff0c;、 和 是用于通知模型在推理过程中响应角色的角色标签。 后面的内容表示模型需要遵循的指令&#xff0c;而 后面的内容传达了当前用户对模型的需求。 后面的内容代表模型的预期输出&#xff0c;也…

学习threejs,实现配合使用WebWorker

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️WebWorker web端多线程 二、…

16-03、JVM系列之:内存与垃圾回收篇(三)

JVM系列之&#xff1a;内存与垃圾回收篇(三) ##本篇内容概述&#xff1a; 1、执行引擎 2、StringTable 3、垃圾回收一、执行引擎 ##一、执行引擎概述 如果想让一个java程序运行起来&#xff0c;执行引擎的任务就是将字节码指令解释/编译为对应平台上的本地机器指令才可以。 简…

小程序 - 美食列表

小程序交互练习 - 美食列表小程序开发笔记 目录 美食列表 功能描述 准备工作 创建项目 配置页面 配置导航栏 启动本地服务器 页面初始数据 设置获取美食数据 设置onload函数 设置项目配置 页面渲染 页面样式 处理电话格式 创建处理电话格式脚本 页面引入脚本 …

Qt6.8 QGraphicsView鼠标坐标点偏差

ui文件拖放QGraphicsView&#xff0c;src文件定义QGraphicsScene赋值给图形视图。 this->scene new QGraphicsScene();ui.graph->setScene(this->scene);对graphicview过滤事件&#xff0c;只能在其viewport之后安装&#xff0c;否则不响应。 ui.graph->viewport…

若依 ruoyi VUE el-select 直接获取 选择option 的 label和value

1、最新在研究若依这个项目&#xff0c;我使用的是前后端分离的方案&#xff0c;RuoYi-Vue-fast(后端) RuoYi-Vue-->ruoyi-ui(前端)。RuoYi-Vue-fast是单应用版本没有区分那么多的modules 自己开发起来很方便&#xff0c;这个项目运行起来很方便&#xff0c;但是需要自定义的…

springboot事务手动回滚报错

捕捉异常之后手动标记回滚事务 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 没有嵌套事务&#xff0c;还是报Transaction rolled back because it has been marked as rollback-only异常错误 查看错误堆栈&#xff0c;service调用的方法外层还套…

使用 LlamaFactory 结合开源大语言模型实现文本分类:从数据集构建到 LoRA 微调与推理评估

文章目录 背景介绍文本分类数据集Lora 微调模型部署与推理期待模型的输出结果 文本分类评估代码 背景介绍 本文将一步一步地&#xff0c;介绍如何使用llamafactory框架利用开源大语言模型完成文本分类的实验&#xff0c;以 LoRA微调 qwen/Qwen2.5-7B-Instruct 为例。 文本分类…

ARM内核与单片机

1.单片机硬件架构如下所示&#xff1a;各种硬件通过总线进行连接。 2.M4内核架构 3.单片机如何工作&#xff1a; 4.CPU是通过读写寄存器来控制GPIO的 5.GPIO的硬件框架&#xff1a;一共有8种模式 &#xff08;1&#xff09;推挽/推挽复用输出。下图先看图1&#xff0c;如果输入…

PHP 命令执行漏洞学习记录

PHP 命令执行 命令函数 作用 例子 system() 执行外部程序,并且显示输出 system(whoami) exec() 执行一个外部程序 echo exec(whoami); shell_exec() 通过shell环境执行命令,并且将完整的输出以字符串的形式返回 echo shell_exec(whoami); passthru() 执行外部程序…