opengl 学习(二)-----你好,三角形
你好,三角形
- 分类
- demo
- 效果
- 解析
分类
opengl c++
demo
#include "glad/glad.h"
#include "glfw3.h"
#include <iostream>
#include <cmath>
#include <vector>using namespace std;/**
* 在学习此节之前,建议将这三个单词先记下来:
- 顶点数组对象:Vertex Array Object,VAO
- 顶点缓冲对象:Vertex Buffer Object,VBO
- 元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO
*//**
* 在OpenGL中,任何事物都在3D空间中,而屏幕和窗口却是2D像素数组,
这导致OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。
3D坐标转为2D坐标的处理过程是
由OpenGL的图形渲染管线(Graphics Pipeline,大多译为管线,
实际上指的是一堆原始图形数据途经一个输送管道,
期间经过各种变化处理最终出现在屏幕的过程)管理的。
图形渲染管线可以被划分为两个主要部分:
第一部分把你的3D坐标转换为2D坐标,
第二部分是把2D坐标转变为实际的有颜色的像素。
这个教程里,我们会简单地讨论一下图形渲染管线,以及如何利用它创建一些漂亮的像素。
*//**
* 当今大多数显卡都有成千上万的小处理核心,
它们在GPU上为每一个(渲染管线)阶段运行各自的小程序,
从而在图形渲染管线中快速处理你的数据。这些小程序叫做着色器(Shader)。
*//**
* 首先,我们以数组的形式传递3个3D坐标作为图形渲染管线的输入,
用来表示一个三角形,这个数组叫做顶点数据(Vertex Data);
顶点数据是一系列顶点的集合。
一个顶点(Vertex)是一个3D坐标的数据的集合。
而顶点数据是用顶点属性(Vertex Attribute)表示的,
它可以包含任何我们想用的数据,
但是简单起见,
我们还是假定
每个顶点只由一个3D位置 和一些颜色值组成的吧。
*//**
* 顶点着色器->图元装配->几何着色器->光栅化阶段->裁切
* OpenGL中的一个片段是OpenGL渲染一个像素所需的所有数据。
*//**
* 片段着色器的主要目的是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。
在现代OpenGL中,
我们必须定义至少一个顶点着色器
和
一个片段着色器(因为GPU中没有默认的顶点/片段着色器)。
出于这个原因,刚开始学习现代OpenGL的时候可能会非常困难,
因为在你能够渲染自己的第一个三角形之前已经需要了解一大堆知识了。
在本节结束你最终渲染出你的三角形的时候,
你也会了解到非常多的图形编程知识。
*//**
* 开始绘制图形之前,我们需要先给OpenGL输入一些顶点数据。
OpenGL是一个3D图形库,
所以在OpenGL中我们指定的所有坐标都是3D坐标(x、y和z)。
OpenGL不是简单地把所有的3D坐标变换为屏幕上的2D像素;
OpenGL仅当3D坐标在3个轴(x、y和z)上-1.0到1.0的范围内时才处理它。
所有在这个范围内的坐标叫做标准化设备坐标(Normalized Device Coordinates),
此范围内的坐标最终显示在屏幕上(在这个范围以外的坐标则不会显示)。
由于我们希望渲染一个三角形,
我们一共要指定三个顶点,
每个顶点都有一个3D位置。
我们会将它们以标准化设备坐标的形式(OpenGL的可见区域)定义为一个float数组。
*/const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);
}int main()
{glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);int success;char infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// fragment shaderunsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// check for shader compile errorsglGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// link shadersunsigned int shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// check for linking errorsglGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);float vertices[] = {-0.5f, -0.5f, 0.0f,0.5f, -0.5f, 0.0f,0.0f, 0.5f, 0.0f};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbindglBindBuffer(GL_ARRAY_BUFFER, 0);// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.glBindVertexArray(0);// uncomment this call to draw in wireframe polygons.//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);// render loop// -----------while (!glfwWindowShouldClose(window)){// input// -----processInput(window);// render// ------glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// draw our first triangleglUseProgram(shaderProgram);glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organizedglDrawArrays(GL_TRIANGLES, 0, 3);// glBindVertexArray(0); // no need to unbind it every time // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)// -------------------------------------------------------------------------------glfwSwapBuffers(window);glfwPollEvents();}// optional: de-allocate all resources once they've outlived their purpose:// ------------------------------------------------------------------------glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);// glfw: terminate, clearing all previously allocated GLFW resources.// ------------------------------------------------------------------glfwTerminate();return 0;
}
效果

解析








混合决定透明效果
测试决定前后次序
渲染管线的顺序:
顶->三->图->剪->光栅->片元->混测
图元转配是指:把变换后的顶点,根据顺序,组成三角形,直线等图元的过程
相关文章:
opengl 学习(二)-----你好,三角形
你好,三角形 分类demo效果解析 分类 opengl c demo #include "glad/glad.h" #include "glfw3.h" #include <iostream> #include <cmath> #include <vector>using namespace std;/** * 在学习此节之前,建议将这…...
mongodb4.2升级到5.0版本,升级到6.0版本, 升级到7.0版本案例
今天一客户想把自己当前使用的mongodb数据库4.2版本升级到7.0版本。难道mongodb能直接跳跃升级吗? 经过几经查找资料,貌似真不行呀。确定升级流程如下: 还得从mongo4.2升级到5.0。其次再从5.0升级到6.0。最后再从6.0升级到7.0。 开始升级之前将数据进行备份 这一步…...
CPU处理器模式与异常
ARM架构中的Exception Level(EL) 在ARM架构中,Exception Level(EL)是一个关键概念,它表示了处理器当前处理异常或中断的层次。ARMv8-A架构定义了四个Exception Levels:EL0、EL1、EL2和EL3&…...
Day 53 |● 1143.最长公共子序列 ● 1035.不相交的线 ● 53. 最大子序和
1143.最长公共子序列 class Solution { public:int longestCommonSubsequence(string text1, string text2) {vector<vector<int>> dp(text1.size()1,vector<int>(text2.size()1,0));int res 0;for(int i 1; i < text1.size(); i){for(int j 1; j <…...
ant-desgin charts双轴图DualAxes,柱状图无法立即显示,并且只有在调整页面大小(放大或缩小)后才开始显示
摘要 双轴图表中,柱状图无法立即显示,并且只有在调整页面大小(放大或缩小)后才开始显示 官方示例代码 在直接复制,替换为个人数据时,出现柱状图无法显示问题 const config {data: [data, data],xFiel…...
获取别人店铺的所有商品API接口
使用淘宝淘口令接口的步骤通常包括: 注册成为淘宝开放平台的开发者:在淘宝开放平台网站上注册账号并完成认证。 创建应用以获取API密钥:在您的开发者控制台中创建一个应用,并获取用于API调用的密钥,如Client ID和Clie…...
成都正信:亲戚借了钱一直不还怎么委婉的说
在中国传统文化中,亲情关系往往被视为最为重要和敏感的部分。当亲戚间发生借贷时,若出现拖欠不还的情形,处理起来尤为棘手。面对这样的尴尬局面,采取委婉而有效的沟通方式至关重要。 张华最近就遇到了这样的困扰。他的表弟去年因急…...
Truenas入门级教程
Truenas入门教程 前言:系统相关配置 采用I3 4160,采用了2块500G的硬盘,内存为8G,两个网卡只用了其中一个,系统安装的是core版本 硬件采用DELL3020MT机箱,自带3个SATA网口,后期网口不够&#…...
窗口函数dense() over(条件)
力扣题目连接 https://leetcode.cn/problems/rank-scores/ 在 SQL 中,DENSE_RANK() 是一个窗口函数,用于计算结果集中每行的稠密排名(dense rank)。DENSE_RANK() 函数会为具有相同排序字段值的行分配相同的排名,但不会…...
蓝牙APP开发实现汽车遥控钥匙解锁汽车智能时代
在现代社会,随着科技的不断发展,汽车已经不再是简单的交通工具,而是与智能科技紧密相连的载体。其中,通过开发APP蓝牙程序实现汽车遥控钥匙成为了一种趋势,为车主带来了便捷与安全的体验。虎克技术公司作为行业领先者&…...
第三天 Kubernetes进阶实践
第三天 Kubernetes进阶实践 本章介绍Kubernetes的进阶内容,包含Kubernetes集群调度、CNI插件、认证授权安全体系、分布式存储的对接、Helm的使用等,让学员可以更加深入的学习Kubernetes的核心内容。 ETCD数据的访问 kube-scheduler调度策略实践 预选与…...
redis小结
1.mysql是数据库,redis是数据库,那么什么时候使用应该使用哪种数据库? redis做缓存是为了缓解mysql的压力,在数据库表数据量上千万,并且访问频繁时,mysql压力增大,在有索引的情况下依旧效果不佳,需要使用…...
PHP伪协议详解
PHP伪协议详解 一、前言1.什么是PHP伪协议?2.什么时候用PHP伪协议? 二、常见的php伪协议php://inputphp://filterzip://与bzip2://与zlib://协议data://phar:// 一、前言 1.什么是PHP伪协议? PHP伪协议是PHP自己支持的一种协议与封装协议,…...
进程:守护进程
一、守护进程的概念 守护进程是脱离于终端控制,且运行在后端的进程。(孤儿进程)守护进程不会将信息显示在任何终端上影响前端的操作,也不会被终端产生的任何信息打断,例如(ctrlc).守护进程独立…...
千里马平台项目管理理念
软件项目的成功和失败和技术关系不大,尤其是应用型软件,不可能有技术难关卡死了项目,大部分问题还是出现在项目管理层面。公司的业务形态是帮助客户构建自己的信息化生态圈,项目管理咨询也是其中的核心内容。 我们的软件项目管理理…...
GB 2312字符集:中文编码的基石
title: GB 2312字符集:中文编码的基石 date: 2024/3/7 19:26:00 updated: 2024/3/7 19:26:00 tags: GB2312编码中文字符集双字节编码区位码规则兼容性问题存储空间优化文档处理应用 一、GB 2312字符集的背景 GB 2312字符集是中国国家标准委员会于1980年发布的一种…...
我的创作周年纪念日
机缘 最初成为创作者的初心:整理自己的知识体系,普及前端知识 实战项目中的经验分享日常工作学习过程中的记录通过文章进行技术交流归纳和整理自己的知识体系 收获 创作的过程中收获: 获得了909粉丝的关注获得了很多正向的反馈,…...
MySQL为什么要用B+树?
二叉树(二叉查找树) 平衡二叉树(B树就是B-树)(解决了二叉查找树的极端情况) Q:具体是怎么解决的呢? A: 树左右两边层数相差不大于1一旦符合条件1的时候,就进行左旋/右…...
今天分享一个好看的输入法皮肤相信每个人心里住着一个少女心我们美化一下她吧
标题: 白日梦皮肤上线,百度输入法助你开启梦幻之旅! 正文: 大家好呀!今天我来给大家安利一款超级梦幻的百度输入法皮肤——“白日梦”系列! 这款皮肤的设计灵感来源于我们内心深处的白日梦,充…...
力扣刷题Days11第二题--141. 环形链表(js)
目录 1,题目 2,代码 2.1快慢指针 2.2,哈希表 3,学习与总结 3.1自己尝试写快慢指针 反思 1,题目 给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达&…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
