LearnOpenGL小练习(QOpenGLWidget版本)

news2025/4/3 4:25:44

你好,三角形

1.绘制两个彼此相连的三角形

画两个独立的三角形,给出两个三角形顶点,使用GL_TRIANGLES绘图即可。

关键代码

void MyOpenglWgt::initializeGL()
{
    initializeOpenGLFunctions();  

    // 1. 创建ShaderProgram着色器:加载顶点着色器代码和片元着色器代码
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,  
        "#version 330 core\n"
        "layout(location = 0) in vec2 aPos;\n"
        "void main() { gl_Position = vec4(aPos, 0.0, 1.0); }"
    );
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main() { FragColor = vec4(1.0, 0.5, 0.2, 1.0); }"
    );
    shaderProgram.link();   

    vao.create();
    vao.bind();
    vbo.create();
    vbo.bind();
    vbo.setUsagePattern(QOpenGLBuffer::DynamicDraw);

    // 顶点数据
    float vertices[] = {
        // 第一个三角形
        -1.0f, -0.5f,   // 左下角
         0.0f, -0.5f,   // 右下角
        -0.5f, 0.5f,   // 顶点

        // 第二个三角形
         0.0f, -0.5f,  // 左下角
         1.0f, -0.5f,  // 右下角
         0.5f,  0.5f,  // 顶点
    };
    vbo.allocate(vertices, sizeof(vertices));  

    // 配置顶点属性
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    vbo.release();
    vao.release();
}

void MyOpenglWgt::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    shaderProgram.bind();  
    vao.bind();            

    glDrawArrays(GL_TRIANGLES, 0, 6); // GL_TRIANGLES:以每三个顶点绘制一个独立的三角形

    vao.release();
    shaderProgram.release();
}

效果图

2.创建相同的两个三角形,但对它们的数据使用不同的VAO和VBO

在初始化时候,直接用两个vao和vbo分别存储两个三角形。
在绘制时,先绑定第一个VAO,绘制第一个三角形,然后绑定第二个VAO,绘制第二个。

关键代码

void MyOpenglWgt::initializeGL()
{
    initializeOpenGLFunctions();
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 330 core\n"
        "layout(location = 0) in vec2 aPos;\n"
        "void main() { gl_Position = vec4(aPos, 0.0, 1.0); }"
    );
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main() { FragColor = vec4(1.0, 0.5, 0.2, 1.0); }"
    );
    shaderProgram.link();

    vao.create();
    vao.bind();
    vbo.create();
    vbo.bind();
    vbo.setUsagePattern(QOpenGLBuffer::DynamicDraw);
    
    // 顶点数据
    float vertices[] = {
        // 第一个三角形
        -1.0f, -0.5f,   // 左下角
         0.0f, -0.5f,   // 右下角
        -0.5f, 0.5f,   // 顶点
    };
    vbo.allocate(vertices, sizeof(vertices));
    
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);
    vbo.release();
    vao.release();

    vao_2.create();
    vao_2.bind();
    vbo_2.create();
    vbo_2.bind();
    vbo_2.setUsagePattern(QOpenGLBuffer::DynamicDraw);

    // 顶点数据
    float vertices2[] = {
        // 第二个三角形
         0.0f, -0.5f,  // 左下角
         1.0f, -0.5f,  // 右下角
         0.5f,  0.5f,  // 顶点
    };
    vbo_2.allocate(vertices2, sizeof(vertices2));
    
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    vbo_2.release();
    vao_2.release();
}

void MyOpenglWgt::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    shaderProgram.bind();
    vao.bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);//绘制第一个三角形
    vao.release();

    vao_2.bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);//绘制第二个三角形
    vao_2.release();
    shaderProgram.release();
}

效果图

3.创建两个着色器程序,第二个程序使用一个不同的片段着色器

在初始化时,再添加一个着色器,修改着色器代码中的FragColor值。
在绘制时,使用不同的着色器绘制三角形即可。

关键代码

void MyOpenglWgt::initializeGL()
{
    initializeOpenGLFunctions();
    // 第一个着色器
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 330 core\n"
        "layout(location = 0) in vec2 aPos;\n"
        "void main() { gl_Position = vec4(aPos, 0.0, 1.0); }"
    );
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main() { FragColor = vec4(1.0, 0.5, 0.2, 1.0); }"
    );
    shaderProgram.link();
    vao.create();
    vao.bind();
    vbo.create();
    vbo.bind();
    vbo.setUsagePattern(QOpenGLBuffer::DynamicDraw);

    // 上传第一个三角形的顶点数据并配置顶点属性
    float vertices[] = {
        // 第一个三角形
        -1.0f, -0.5f,   // 左下角
         0.0f, -0.5f,   // 右下角
        -0.5f, 0.5f,   // 顶点
    };
    vbo.allocate(vertices, sizeof(vertices));

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);
    vbo.release();
    vao.release();

    // 第二个着色器
    shaderProgram_2.addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 330 core\n"
        "layout(location = 0) in vec2 aPos;\n"
        "void main() { gl_Position = vec4(aPos, 0.0, 1.0); }"
    );
    shaderProgram_2.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main() { FragColor = vec4(0.9, 0.6, 0.8, 1.0); }"
    );
    shaderProgram_2.link();
    vao_2.create();
    vao_2.bind();
    vbo_2.create();
    vbo_2.bind();
    vbo_2.setUsagePattern(QOpenGLBuffer::DynamicDraw);

     // 上传第二个三角形的顶点数据并配置顶点属性
    float vertices2[] = {
        // 第二个三角形
         0.0f, -0.5f,  // 左下角
         1.0f, -0.5f,  // 右下角
         0.5f,  0.5f,  // 顶点
    };
    vbo_2.allocate(vertices2, sizeof(vertices2));

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    vbo_2.release();
    vao_2.release();
}

void MyOpenglWgt::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 绘制第一个三角形
    shaderProgram.bind();
    vao.bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    vao.release();
    shaderProgram.release();
    
	// 绘制第二个三角形
    shaderProgram_2.bind();
    vao_2.bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    vao_2.release();
    shaderProgram_2.release();
}

效果图

着色器

1.修改顶点着色器让三角形上下颠倒

使用两个相同的三角形顶点数据,在顶点着色器中将y轴的值改为负值即可。

关键代码

void MyOpenglWgt::initializeGL()
{
    initializeOpenGLFunctions();
     // 顶点数据
    float vertices[] = {
        -1.0f, -0.5f,   // 左下角
         0.0f, -0.5f,   // 右下角
        -0.5f, 0.0f,   // 顶点
    };
    
    // 第一个着色器
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 330 core\n"
        "layout(location = 0) in vec2 aPos;\n"
        "void main() { gl_Position = vec4(aPos, 0.0, 1.0); }"
    );
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main() { FragColor = vec4(1.0, 0.5, 0.2, 1.0); }"
    );
    shaderProgram.link();
    vao.create();
    vao.bind();
    vbo.create();
    vbo.bind();
    vbo.setUsagePattern(QOpenGLBuffer::DynamicDraw);
    vbo.allocate(vertices, sizeof(vertices));

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);
    vbo.release();
    vao.release();

    // 第二个着色器
    shaderProgram_2.addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 330 core\n"
        "layout(location = 0) in vec2 aPos;\n"
        "void main() { gl_Position = vec4(aPos.x, -aPos.y, 0.0, 1.0); }"
    );
    shaderProgram_2.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main() { FragColor = vec4(0.9, 0.6, 0.8, 1.0); }"
    );
    shaderProgram_2.link();
    vao_2.create();
    vao_2.bind();
    vbo_2.create();
    vbo_2.bind();
    vbo_2.setUsagePattern(QOpenGLBuffer::DynamicDraw);
    vbo_2.allocate(vertices, sizeof(vertices));

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    vbo_2.release();
    vao_2.release();
}

效果图
在这里插入图片描述

2.使用uniform定义一个水平偏移量,在顶点着色器中使用这个偏移量把三角形移动到屏幕右侧

在顶点着色器中,定义变量offset,并将该值加到x轴上。

uniform float offset;
void main() { gl_Position = vec4(aPos.x + offset, aPos.y, 0.0, 1.0);

Uniform的设置时机很重要: 在设置uniform之前,必须确保着色器程序已经绑定,否则setUniformValue可能不起作用。

shaderProgram_2.bind();
shaderProgram_2.setUniformValue("offset", 0.8f);
shaderProgram_2.release();

关键代码

void MyOpenglWgt::initializeGL()
{
    initializeOpenGLFunctions();

    // 顶点数据
    float vertices[] = {
        -1.0f, -0.5f,   // 左下角
         0.0f, -0.5f,   // 右下角
        -0.5f, 0.0f,   // 顶点
    };

    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 330 core\n"
        "layout(location = 0) in vec2 aPos;\n"
        "void main() { gl_Position = vec4(aPos, 0.0, 1.0); }"
    );
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main() { FragColor = vec4(1.0, 0.5, 0.2, 1.0); }"
    );
    shaderProgram.link();

    vao.create();
    vao.bind();
    vbo.create();
    vbo.bind();
    vbo.setUsagePattern(QOpenGLBuffer::DynamicDraw);
    vbo.allocate(vertices, sizeof(vertices));
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);
    vbo.release();
    vao.release();

    // 第二个着色器
    shaderProgram_2.addShaderFromSourceCode(QOpenGLShader::Vertex,
        "#version 330 core\n"
        "layout(location = 0) in vec2 aPos;\n"
        "uniform float offset;\n"
        "void main() { gl_Position = vec4(aPos.x + offset, aPos.y, 0.0, 1.0); }"
    );
    shaderProgram_2.addShaderFromSourceCode(QOpenGLShader::Fragment,
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main() { FragColor = vec4(0.9, 0.6, 0.8, 1.0); }"
    );
    shaderProgram_2.link();
    vao_2.create();
    vao_2.bind();
    vbo_2.create();
    vbo_2.bind();
    vbo_2.setUsagePattern(QOpenGLBuffer::DynamicDraw);
    vbo_2.allocate(vertices, sizeof(vertices));
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);
    vbo_2.release();
    vao_2.release();
}

void MyOpenglWgt::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);

    // 绘制第一个三角形
    shaderProgram.bind();
    vao.bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    vao.release();
    shaderProgram.release();

    // 绘制第二个三角形
    shaderProgram_2.bind();
    vao_2.bind();
    shaderProgram_2.setUniformValue("offset", 0.8f);// 在设置uniform之前,必须确保着色器程序已经绑定
    glDrawArrays(GL_TRIANGLES, 0, 3);
    vao_2.release();
    shaderProgram_2.release();
}

效果图
在这里插入图片描述

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

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

相关文章

基于OpenCV+MediaPipe手部追踪

一、技术栈 1. OpenCV(Open Source Computer Vision Library) 性质:开源计算机视觉库(Library) 主要功能: 图像/视频的基础处理(读取、裁剪、滤波、色彩转换等) 特征检测&#xf…

十五届蓝桥杯省赛Java B组(持续更新..)

目录 十五届蓝桥杯省赛Java B组第一题:报数第二题:类斐波那契数第三题:分布式队列第四题:食堂第五题:最优分组第六题:星际旅行第七题:LITS游戏第八题:拼十字 十五届蓝桥杯省赛Java B…

蓝耘平台API深度剖析:如何高效实现AI应用联动

目录 一、蓝耘平台简介 1.1 蓝耘通义大模型 1.2 蓝耘云计算资源 1.3 蓝耘API与微服务 二、 蓝耘平台应用联动场景 2.1 数据采集与预处理联动 2.2 模型推理与后端服务联动 2.3 跨平台联动 三、蓝耘平台注册体验功能 3.1 注册 3.2 体验蓝耘MaaS平台如何使用海螺AI生成视频…

缓存 “三剑客”

缓存 “三剑客” 问题 如何保证 Redis 缓存和数据库的一致性? 1. 缓存穿透 缓存穿透是指请求一个不存在的数据,缓存层和数据库层都没有这个数据,这种请求会穿透缓存直接到数据库进行查询 解决方案: 1.1 缓存空值或特殊值 查一…

ComfyUi教程之阿里的万象2.1视频模型

ComfyUi教程之阿里的万象2.1视频模型 官网Wan 2.1 特点 一、本地安装1.1克隆仓库1.2 安装依赖(1.3)下载模型(1.4)CUDA和CUDNN 二、 使用体验(2.1)官方例子(2.2)执行过程(…

Leetcode 寻找两个正序数组的中位数

💯 完全正确!!你这段话可以直接当作这道题的**“思路总览”模板答案**了,结构清晰、逻辑严谨、几乎没有遗漏任何关键点👏 不过我可以帮你稍微精炼一下语言,使它在保留你原本意思的基础上更具表达力和条理性…

C#测试Excel开源组件ExcelDataReader

使用微软的com组件Microsoft.office.Interop.Excel读写Excel文件虽然可用,但是列多、行多的时候速度很慢,之前测试过Sylvan.Data.Excel包的用法,如果只是读取Excel文件内容的话,还可以使用ExcelDataReader包,后者是C#开…

手机零售行业的 AI 破局与创新降本实践 | OceanBase DB大咖说

OceanBase《DB 大咖说》第 20 期,我们邀请了九机与九讯云的技术总负责人,李远军,为我们分享手机零售企业如何借力分布式数据库OceanBase,赋能 AI 场景,并通过简化架构实现成本管控上的突破与创新。 李远军于2016年加入…

SpringBoot整合LogStash,LogStash采集服务器日志

LogStash 1. 下载 版本支持兼容表https://www.elastic.co/cn/support/matrix 版本: 7.16.x 的最后一个版本 https://www.elastic.co/downloads/past-releases/logstash-7-16-3 需要提前安装好jdk1.8和ES, 此处不在演示 2. 安装 tar -xvf logstash-7.16.3-linux-x86_64.tar.gz…

目前市场上,好用的校招系统是哪个?

在数字化浪潮的推动下,校园招聘已从传统的“海投简历线下宣讲”模式全面转向智能化、数据化。面对每年数百万应届生的激烈竞争,企业如何在短时间内精准筛选人才、优化招聘流程、降低人力成本?答案或许藏在AI驱动的校招管理系统中。而在这场技…

SharpBrowser:用C#打造超快的个性化开源浏览器!

推荐一个基于.Net 8 和 CefSharp开发的开源浏览器。 01 项目简介 SharpBrowser 是一个用 C# 和 CefSharp 开发的全功能网页浏览器。它声称是最快的开源 C# 网页浏览器,渲染网页的速度比谷歌浏览器还快,因为其使用轻量级的 CEF 渲染器。 经过比较所有可…

【新模型速递】PAI一键云上零门槛部署DeepSeek-V3-0324、Qwen2.5-VL-32B

DeepSeek近期推出了“DeepSeek-V3-0324”版本,据测试在数学推理和前端开发方面的表现已优于 Claude 3.5 和 Claude 3.7 Sonnet。 阿里也推出了多模态大模型Qwen2.5-VL的新版本--“Qwen2.5-VL-32B-Instruct”,32B参数量实现72B级性能,通杀图文…

【Elasticsearch基础】基本核心概念介绍

Elasticsearch作为当前最流行的分布式搜索和分析引擎,其强大的功能背后是一套精心设计的核心概念体系。本文将深入解析Elasticsearch的五大核心概念,帮助开发者构建坚实的技术基础,并为高效使用ES提供理论支撑。 1 索引(Index&…

Github 热点项目 awesome-mcp-servers MCP 服务器合集,3分钟实现AI模型自由操控万物!

【今日推荐】超强AI工具库"awesome-mcp-servers"星数破万! ① 百宝箱式服务模块:AI能直接操作浏览器、读文件、连数据库,比如让AI助手自动整理Excel表格,三分钟搞定全天报表; ② 跨领域实战利器:…

SpringMVC 拦截器(Interceptor)

一.拦截器 假设有这么一个场景,一个系统需要用户登录才能进入,在检验完用户的信息后对页面进行了跳转。但是如果我们直接输入跳转的url,可以绕过用户信息校验(用户登录),直接进入系统。 因此我们引入了使…

03-SpringBoot3入门-配置文件(自定义配置及读取)

1、自定义配置 # 自定义配置 zbj:user:username: rootpassword: 123456# 自定义集合gfs:- a- b- c2、读取 1)User类 package com.sgu.pojo;import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.spring…

【蓝桥杯每日一题】3.28

🏝️专栏: 【蓝桥杯备篇】 🌅主页: f狐o狸x "今天熬的夜,会变成明天奖状的闪光点!" 目录 一、唯一的雪花 题目链接 题目描述 解题思路 解题代码 二、逛画展 题目链接 题目描述 解题思路 解题代…

万字长文详解Text-to-SQL

什么是Text-to-SQL 在各个企业数据量暴涨的现在,Text-to-SQL越来越重要了,所以今天就来聊聊Text-to-SQL。 Text-to-SQL是一种将自然语言查询转换为数据库查询的技术。它可以让用户通过自然语言来查询数据库,而不需要编写复杂的SQL语句。 T…

【Linux】动静态库的制作与使用

一.对软硬链接的补充 1、无法对目录进行硬链接 为什么呢? 首先,我们在访问文件时,每一个文件都会有自己的dentry结构,这些结构会在内存中维护一棵路径树,来快速进行路径查找。但是如果某个节点直接使用硬链接到了根节…

ubuntu22.04 如何安装 ch341 驱动

前言 本篇是介绍ubuntu22.04如何安装 ch341 驱动,并对其中遇到的问题进行整理。 一、流程 1.1 查看CH340驱动 首先是查看ubuntu22.04系统自带的驱动,用以下命令即可 ls /lib/modules/$(uname -r)/kernel/drivers/usb/serial 然后会跳出以下界面&…