C#使用OpenTK绘制3D可拖动旋转图形三棱锥

接上篇,绘制着色矩形

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;
        }
    }
}

 运行如图:

可以拖动旋转:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《C++11》nullptr介绍:从NULL说起

在C11之前&#xff0c;我们通常使用NULL来表示空指针。然而&#xff0c;NULL在C中有一些问题和限制&#xff0c;这就是C11引入nullptr的原因。本文将详细介绍nullptr的定义、用法和优点。 1. NULL的问题 在C中&#xff0c;NULL实际上是一个整数0&#xff0c;而不是一个真正的…

Postman 接口测试平替工具,可视化开发省事!

在软件开发的漫长旅程中&#xff0c;接口测试工具一直是开发者的得力助手。Postman 作为全球知名的接口测试工具&#xff0c;长期占据市场主导地位。然而&#xff0c;随着国产工具的崛起&#xff0c;越来越多的开发者开始寻找更适合中国开发者的替代方案。一款 Apifox&#xff…

代码随想录算法训练营day20(0113)

1.二叉搜索树的最近公共祖先 在上次做完二叉树的最近公共祖先后&#xff0c;此题就显得比较简单了。不过要拓展一下&#xff0c;因为二叉搜索树有一些特性的&#xff0c;可以更加方便的解题。 题目 235. 二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节…

使用C# CEFSharp在WPF中开发桌面程序实现同一网站多开功能

在网络商业运营领域&#xff0c;同时运营多个淘宝店铺的现象屡见不鲜。为了满足这一需求&#xff0c;实现同一网址的多开功能变得尤为关键。这一需求虽然实用&#xff0c;但实现起来却面临诸多挑战。在这个过程中&#xff0c;技术人员们也经历了不少喜怒哀乐。 开发经历回顾 …

Shell 经典面试例题

1.shell 脚本写出检测 /tmp/size.log 文件如果存在显示它的内容&#xff0c;不存在则创建一个文件将创建时间写入。 编写脚本&#xff1a; #!/bin/bash FILE"/tmp/size.log" if [ -f "$FILE" ]; then echo "文件存在&#xff0c;显示文件内容&…

移动云自研云原生数据库入围国采!

近日&#xff0c;中央国家机关2024年度事务型数据库软件框架协议联合征集采购项目产品名单正式公布&#xff0c;移动云自主研发的云原生数据库产品顺利入围。这一成就不仅彰显了移动云在数据库领域深耕多年造就的领先技术优势&#xff0c;更标志着国家权威评审机构对移动云在数…

Centos 宝塔安装

yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 安装成功界面 宝塔说明文档 https://www.bt.cn/admin/servers#wcu 或者可以注册宝塔账号 1 快速部署 安装docker 之后 2 需要在usr/bin下下载do…

ros2笔记-6.2 使用urdf创建机器人模型

本节主要跟着小鱼老师的视频操作&#xff0c;不同的仿真平台有不同的建模语言&#xff0c;但是几乎都支持URDF。 本节使用URDF创建一个机器人模型。 6.2.1 帮机器人创建一个身体 URDF使用XML来描述机器人的结构和传感器、执行器等信息。 在chapt6/chap6_ws/src创建功能包:r…

文章复现—面向配电网韧性提升的移动储能预布局与动态调度策略

目录 一、主要内容&#xff1a; 二、实际运行效果&#xff1a; 三、文章介绍&#xff1a; 四、完整代码数据下载&#xff1a; 一、主要内容&#xff1a; &#xff08;matlab代码&#xff09;该程序复现《面向配电网韧性提升的移动储能预布局与动态调度策略》&#xff0c;具…

【ASP.NET学习】Web Forms创建Web应用

文章目录 什么是 Web Forms&#xff1f;ASP.NET Web Forms - HTML 页面用 ASP.NET 编写的 Hello RUNOOB.COM它是如何工作的&#xff1f;经典 ASP ASP.NET Web Forms - 服务器控件经典 ASP 的局限性ASP.NET - 服务器控件ASP.NET - HTML 服务器控件ASP.NET - Web 服务器控件ASP.N…

python-leetcode-旋转图像

48. 旋转图像 - 力扣&#xff08;LeetCode&#xff09; class Solution:def rotate(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""n len(matrix)# 矩阵转置for i in range(n):for…

GPT 系列论文精读:从 GPT-1 到 GPT-4

学习 & 参考资料 前置文章 Transformer 论文精读 机器学习 —— 李宏毅老师的 B 站搬运视频 自监督式学习(四) - GPT的野望[DLHLP 2020] 來自猎人暗黑大陆的模型 GPT-3 论文逐段精读 —— 沐神的论文精读合集 GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【论文精读】…

《计算机网络》课后探研题书面报告_了解PPPoE协议

PPPoE协议的工作原理与应用分析 摘 要 PPPoE&#xff08;Point-to-Point Protocol over Ethernet&#xff09;是一种广泛应用于宽带接入的网络协议&#xff0c;特别是在DSL&#xff08;数字用户线路&#xff09;和光纤网络中具有重要的应用价值。PPPoE结合了PPP协议的认证、加…

玩转大语言模型——langchain调用ollama视觉多模态语言模型

系列文章目录 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 langchain调用ollama视觉多模态语言模型 系列文章目录前言使用Ollama下载模型查找模型下载模型 测试模型ollama测试langchain测试加载图片加载模型…

开始使用Panuon开源界面库环境配置并手写VS2019高仿界面

1. Panuon环境配置 1.1. 通过Nuget 安装 Panuon.WPF.UI1.2. xaml引用命名空间1.3. using Panuon.WPF.UI; 2. VS2019 view 2.1. 设置窗体尺寸和title2.2. 添加静态资源 2.2.1. 什么是静态资源 2.3. 主Grid 2.3.1. 盒子模型2.3.2. 嵌套布局 3. 总结 1. Panuon环境配置 1.1. 通…

[Git] 深入理解 Git 的客户端与服务器角色

Git 的一个核心设计理念是 分布式&#xff0c;每个 Git 仓库都可以既是 客户端&#xff0c;也可以是 服务器。为了更好地理解这一特性&#xff0c;我们通过一个实际的 GitHub 远程仓库和本地仓库的场景来详细说明 Git 如何在客户端和服务器之间协作&#xff0c;如何独立地进行版…

基于考研概率论知识解读 Transformer:为何自注意力机制要除以根号 dk

Transformer自注意力机制中除以 d k \sqrt{d_k} dk​ ​深度剖析 【 Transformer 系列&#xff0c;故事从 d k \sqrt{d_k} dk​ ​说起】 LLM这么火&#xff0c;Transformer厥功甚伟&#xff0c;某天心血来潮~&#xff0c;再去看看&#xff01; 它长这个样子&#xff1a; 深入…

使用 selenium-webdriver 开发 Web 自动 UI 测试程序

优缺点 优点 有时候有可能一个改动导致其他的地方的功能失去效果&#xff0c;这样使用 Web 自动 UI 测试程序可以快速的检查并定位问题&#xff0c;节省大量的人工验证时间 缺点 增加了维护成本&#xff0c;如果功能更新过快或者技术更新过快&#xff0c;维护成本也会随之提高…

【Redis】初识分布式系统

目录 单机架构 分布式系统 应用数据分离架构 应用服务集群架构 读写分离/主从分离架构 冷热分离架构 垂直分库 微服务架构 分布式名词概念 本篇博文&#xff0c;将根据分布式系统的演进一步一步介绍每一种架构的形式&#xff0c;最后为大家总结了一些分布式中常用的…

微服务之松耦合

参考&#xff1a;https://microservices.io/post/architecture/2023/03/28/microservice-architecture-essentials-loose-coupling.html There’s actually two different types of coupling: runtime coupling - influences availability design-time coupling - influences…