LearnOpenGL(二)之三角形

2024-04-22 00:12
文章标签 三角形 learnopengl

本文主要是介绍LearnOpenGL(二)之三角形,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、重要概念

  • 顶点数组对象:Vertex Array Object,VAO
  • 顶点缓冲对象:Vertex Buffer Object,VBO
  • 元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO

以数组的形式传递3个3D坐标作为图形渲染管线的输入,用来表示一个三角形,这个数组叫做顶点数据(Vertex Data);顶点数据是一系列顶点的集合。
一个顶点(Vertex)是一个3D坐标的数据的集合。而顶点数据是用顶点属性(Vertex Attribute)表示的,它可以包含任何我们想用的数据。

顶点着色器是图形渲染管线中的一个阶段,它负责处理输入顶点数据并将其转换为裁剪空间(Clip Space)或者屏幕空间(Screen Space)的坐标。
顶点着色器通常是图形渲染中的第一个阶段,在渲染过程中,每个顶点都会经过顶点着色器的处理。

片段着色器的主要目的是计算一个像素的最终颜色,这也是所有

OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的

数据(比如光照、阴影、光的颜色等等),这些数据可以被用来

计算最终像素的颜色。

在所有对应颜色值确定以后,最终的对象将会被传到最后一个阶

段,我们叫做Alpha测试和混合(Blending)阶段

这个阶段检测片段的对应的深度(和模板(Stencil))值,用它们来

判断这个像素是其它物体的前面还是后面,决定是否应该丢弃。

这个阶段也会检查alpha值(alpha值定义了一个物体的透明度)

并对物体进行混合(Blend)。所以,即使在片段着色器中计算出来

了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜

色也可能完全不同。

二、顶点输入

OpenGL不是简单地把所有的3D坐标变换为屏幕上的2D像素;

OpenGL仅当3D坐标在3个轴(x、y和z)上-1.0到1.0的范围内时

才处理它。所有在这个范围内的坐标叫做标准化设备坐标

(Normalized Device Coordinates),此范围内的坐标最终显示在屏

幕上(在这个范围以外的坐标则不会显示)。

通过使用由glViewport函数提供的数据,进行视口变换(Viewport

Transform),标准化设备坐标(Normalized Device Coordinates)会

变换为屏幕空间坐标(Screen-space Coordinates)。所得的屏幕空

间坐标又会被变换为片段输入到片段着色器中。 定义这样的顶点

数据以后,我们会把它作为输入发送给图形渲染管线的第一个处

理阶段:顶点着色器。它会在GPU上创建内存用于储存我们的顶

点数据,还要配置OpenGL如何解释这些内存,并且指定其如何

发送给显卡。顶点着色器接着会处理我们在内存中指定数量的顶

点。

我们通过顶点缓冲对象(Vertex Buffer Objects, VBO)管理这个内

存,它会在GPU内存(通常被称为显存)中储存大量顶点。使用

这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡

上,而不是每个顶点发送一次。从CPU把数据发送到显卡相对较

慢,所以只要可能我们都要尝试尽量一次性发送尽可能多的数

据。当数据发送至显卡的内存中后,顶点着色器几乎能立即访问

顶点,这是个非常快的过程。

三、链接顶点属性

//顶点数据:

float vertices[] = {

-0.5f,  -0.5f,  0.0f,

 0.5f,  -0.5f,  0.0f,

 0.0f,   0.5f,  0.0f

};

顶点数据会被解析为下面这样子:

  • 位置数据被储存为32位(4字节)浮点值。
  • 每个位置包含3个这样的值。
  • 在这3个值之间没有空隙(或其他值)。这几个值在数组中紧密排列(Tightly Packed)。
  • 数据中第一个值在缓冲开始的位置。

使用glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据(应用到逐个顶点属性上):

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);

glEnableVertexAttribArray(0);

  • 第一个参数指定我们要配置的顶点属性。在顶点着色器中使用layout(location = 0)定义了position顶点属性的位置值,它可以把顶点属性的位置值设置为0。因为我们希望把数据传递到这一个顶点属性中,所以这里我们传入0
  • 第二个参数指定顶点属性的大小。顶点属性是一个vec3,它由3个值组成,所以大小是3。
  • 第三个参数指定数据的类型,这里是GL_FLOAT(GLSL中vec*都是由浮点数值组成的)。
  • 下个参数定义我们是否希望数据被标准化(Normalize)。如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。我们把它设置为GL_FALSE。
  • 第五个参数叫做步长(Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在3个float之后,我们把步长设置为3 * sizeof(float)。要注意的是由于我们知道这个数组是紧密排列的(在两个顶点属性之间没有空隙)我们也可以设置为0来让OpenGL决定具体步长是多少(只有当数值是紧密排列时才可用)。一旦我们有更多的顶点属性,我们就必须更小心地定义每个顶点属性之间的间隔(这个参数的意思简单说就是从这个属性第二次出现的地方到整个数组0位置之间有多少字节)。
  • 最后一个参数的类型是void*,所以需要我们进行这个奇怪的强制类型转换。它表示位置数据在缓冲中起始位置的偏移量(Offset)。由于位置数据在数组的开头,所以这里是0。
//关键代码如下
#include <iostream>
#include <QDebug>
#include <glad/glad.h>
#include <GLFW/glfw3.h>int main(int argc, char *argv[])
{glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //mac os
#endifGLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);if (window == NULL){qDebug() << "Failed to create GLFW window";glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){qDebug() << "Failed to initialize GLAD";return -1;}//glViewport(0, 0, 800, 600);// 0. 当我们渲染一个物体时要使用着色器程序//顶点着色器unsigned int vertexShader;vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);// check for shader compile errorsint  success;char infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if(!success){glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog;}//片段着色器unsigned int fragmentShader;fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if(!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog;}//把顶点和片段着色器附加到程序对象上unsigned int shaderProgram;shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if(!success){glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);//顶点数据:float vertices[] = {-0.5f, -0.5f, 0.0f,// left0.5f, -0.5f, 0.0f,// right0.0f,  0.5f, 0.0f,// top};// 1. 复制顶点数组到缓冲中供OpenGL使用unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glBindVertexArray(VAO);// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 2. 设置顶点属性指针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);//   glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);/* Loop until the user closes the window */while (!glfwWindowShouldClose(window)){processInput(window);glClearColor(0.2f, 0.3f, 0.3f, 1.0f);/* Render here */glClear(GL_COLOR_BUFFER_BIT);// 3. 绘制物体glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);/* Swap front and back buffers */glfwSwapBuffers(window);/* Poll for and process events */glfwPollEvents();}// optional: de-allocate all resources once they've outlived their purpose:glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);glfwTerminate();return 0;
}

代码下载:点击跳转

觉得有帮助的话,打赏一下呗。。

           

这篇关于LearnOpenGL(二)之三角形的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/924383

相关文章

【WebGPU Unleashed】1.1 绘制三角形

一部2024新的WebGPU教程,作者Shi Yan。内容很好,翻译过来与大家共享,内容上会有改动,加上自己的理解。更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加微信号:digital_twin123 在 3D 渲染领域,三角形是最基本的绘制元素。在这里,我们将学习如何绘制单个三角形。接下来我们将制作一个简单的着色器来定义三角形内的像素

CSS实现DIV三角形

本文内容收集来自网络 #triangle-up {width: 0;height: 0;border-left: 50px solid transparent;border-right: 50px solid transparent;border-bottom: 100px solid red;} #triangle-down {width: 0;height: 0;bor

双指针(5)_单调性_有效三角形的个数

个人主页:C++忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创 双指针(5)_单调性_有效三角形的个数 收录于专栏【经典算法练习】 本专栏旨在分享学习C++的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 1. 题目链接: 2.题目描述 : 3.解法 :     解法一(暴力枚举) :     算法思路 :     代码展示 : 暴力枚

利用向量积(叉积)计算三角形的面积和多边形的面积(hdu2036)

开始撸计算几何题目了。。。。。。。 预备知识:叉乘求多边形面积 参考证明资料: 公式证明: http://www.cnblogs.com/xiexinxinlove/p/3708147.html 高中知识: http://wenku.baidu.com/view/867e6edfad51f01dc281f11a.html #include<stdio.h>#inclu

拼接三角形

/********************************************************************************* 问题描述: 牛牛手里有N根木棒,分别编号为1~N,现在他从N根里想取出三根木棒,使得三根木棒构成一个三角形,你能计算出牛牛有多少种取法吗?(考虑两种取法中使用的木棒编号有一个不一样就认为是不同的取法)。  输入描述: 首先输

OpenGL/GLUT实践:实现反弹运动的三角形动画与键盘控制(电子科技大学信软图形与动画Ⅱ实验)

源码见GitHub:A-UESTCer-s-Code 文章目录 1 运行效果2 实验过程2.1 环境配置2.2 绘制三角形2.2.1 渲染函数2.2.2 主函数2.2.3 运行结果 2.3 调整窗口大小2.4 简单动画与按键控制2.4.1 简单旋转2.4.2 键盘控制 2.5 窗口反弹动画2.5.1 处理窗口大小变化2.5.2 渲染函数2.5.3 定时器2.5.4 控制速度

CSS详解:绘制三角形过程

前言 本文旨在用最简单的方式展示CSS border绘制三角形的各种方法,虽然用css 绘制三角形已经不是什么新鲜事了,不过,这篇文章将会尽力展示最全的三角形各种绘制方式。 附送一个三角形在线生成器 原理-盒子模型 如上图,这是一个盒子模型的结构,分为四个区域,content、padding、border, margin 。而本次示例主要用到的是盒子模型中的content和

★ 算法OJ题 ★ 力扣611 - 有效三角形的个数

Ciallo~(∠・ω< )⌒☆ ~ 今天,椎名日和将和大家一起做一道双指针算法题--有效三角形的个数~ 目录 一  题目 二  算法解析 三  编写算法 一  题目 二  算法解析 给三个数,判断是否能构成三角形的条件:两个较小的数相加大于第三个数。 解法⼀:暴力求解 算法思路:三层 for 循环枚举出所有的三元组,并且判断是否能构成三⻆形。(会超时)

MATLAB 计算三角形的外接圆心和半径(84)

MATLAB 计算三角形的外接圆心和半径(84) 一、算法介绍二、算法实现1.代码 一、算法介绍 计算三角形的外接圆心和半径,可视化显示结果 二、算法实现 1.代码 % 设置三个点的坐标A = [1, 1];B = [4,

有效三角形个数问题

目录 一·题目简述: 二·思路总结: 2·1不被认可的暴力破解思路: 2·2优化后的思路: 2·2·1优化后的判断三角形方法: 2·2·2 定一动二指针朝内筛选遍历:  三·解答代码: 一·题目简述: leetcode链接:. - 力扣(LeetCode)  二·思路总结: 2·1不被认可的暴力破解思路: 想必大家看到这道题首先一定想的就是三次循环嵌套,然后