OpenGL简介

官网:OpenGL - The Industry Standard for High Performance Graphics

中文官网:主页 - LearnOpenGL CN

OpenGL(Open Graphics Library)是一种跨语言、跨平台的图形编程接口,主要用于渲染二维和三维矢量图形。它由一个庞大的函数库组成(只有头文件声明,由各家厂家自己实现内容),允许开发者通过编程方式与图形硬件进行交互,从而实现高效、复杂的图形渲染。

以下是OpenGL的一些关键特点和用途:

1. 跨平台和跨语言

  • OpenGL可以在多种操作系统上运行,如Windows、macOS、Linux、Android和iOS等。

  • 它支持多种编程语言,包括C、C++、Python、Java等。

2. 功能强大

  • OpenGL提供了丰富的图形渲染功能,包括几何图形绘制、纹理映射、光照处理、阴影计算、着色器编程等。

  • 它可以用于创建复杂的三维场景,支持实时渲染和交互式图形应用。

3. 硬件加速

  • OpenGL通过与图形硬件(如GPU)紧密配合,利用硬件加速来提高图形渲染的性能。

  • 这使得它在游戏开发、科学计算可视化、虚拟现实等领域表现出色。

4. 可扩展性

  • OpenGL通过扩展机制不断引入新功能,以适应图形硬件和图形技术的发展。

  • 开发者可以通过扩展来访问最新的图形硬件特性。

5. 着色器编程

  • OpenGL支持着色器语言(如GLSL),允许开发者编写自定义的顶点着色器和片元着色器。

  • 着色器编程可以实现复杂的视觉效果,如高级光照模型、动画、粒子系统等。

6. 应用场景

  • 游戏开发:许多游戏引擎(如Unity和Unreal Engine)在底层使用OpenGL或类似技术进行图形渲染。

  • 科学计算与可视化:用于医学成像、气象数据可视化等。

  • 虚拟现实(VR)和增强现实(AR):OpenGL可以高效地渲染沉浸式三维环境。

  • 工业设计与建模:用于CAD软件和三维建模工具。

7. 版本与兼容性

  • OpenGL有多个版本,从早期的1.x版本到现代的4.x版本。现代版本(如OpenGL 4.x)引入了更多高级功能,如计算着色器和多线程渲染。

  • 为了保证兼容性,OpenGL还提供了兼容性上下文(Compatibility Profile)和核心上下文(Core Profile)。

8. 与OpenGL ES的关系

  • OpenGL ES是OpenGL的一个子集,专为嵌入式设备(如移动设备和低功耗设备)设计。

  • 它在功能上与OpenGL相似,但进行了优化以适应移动设备的硬件限制。

9. 与其他图形API的比较

  • 与DirectX:OpenGL是跨平台的,而DirectX主要运行在Windows系统上。两者在功能上类似,但在生态系统和开发工具上有所不同。

  • 与Vulkan:Vulkan是OpenGL的后继者,提供了更底层的硬件访问和更高的性能,但学习曲线更陡峭。

总之,OpenGL是一个功能强大且广泛应用的图形编程接口,它为开发者提供了一个高效、灵活的方式来创建复杂的图形应用程序。

使用流程

初步使用(introduction)

QT中使用OpenGL使用QOpenGLWidget类,需要自己实例化这个类并且重写initializeGL,resizeGL,paintGL这三个保护的虚函数。

myopenglwidget.h

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H#include <QWidget>
#include <QOpenGLWidget>
#include <qopenglfunctions_3_3_core.h>
#include  <QOpenGLFunctions_4_5_Core> //这是最新版本class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{Q_OBJECT
public:explicit MyOpenGLWidget(QWidget *parent = nullptr);protected:virtual void initializeGL();virtual void resizeGL(int w, int h);virtual void paintGL();signals:};#endif // MYOPENGLWIDGET_H

myopenglwidget.cpp

#include "myopenglwidget.h"MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions(); //初始化OpenGL函数,将QT里的函数指针指向显卡的函数。
}void MyOpenGLWidget::resizeGL(int w, int h)
{}void MyOpenGLWidget::paintGL()
{//需要先初始化在使用glClearColor(0.2f,0.2f,0.5f,0.5f); //设置状态glClear(GL_COLOR_BUFFER_BIT); //使用状态
}

VAO和VBO

顶点着色器:

他会在GPU上创建对象,用于存储我们的顶点数据,通过顶点缓存对象(Vertex Buffer Objects,VBO)管理。类型是:GL_ARRAY_BUFFER

配置OpenGL如何解释这些内存:

通过顶点数组对象(Vertex Array Objects,VAO)管理。

#include "myopenglwidget.h"//创建VBO和VAO对象,并赋予ID
unsigned int VBO,VAO;
float vertices[] = {-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f,0.0f,0.5f,0.0f
};MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions(); //初始化OpenGL函数,将QT里的函数指针指向显卡的函数。//创建VBO和VAO对象,并赋予IDglGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);//绑定VBO和VAO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO VBO 进行休息。glBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER,0);}void MyOpenGLWidget::resizeGL(int w, int h)
{}void MyOpenGLWidget::paintGL()
{//需要先初始化在使用glClearColor(0.2f,0.2f,0.2f,1.0f); //设置状态glClear(GL_COLOR_BUFFER_BIT); //使用状态glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES,0,3);
}

编译链接着色器

#include "myopenglwidget.h"//创建VBO和VAO对象,并赋予ID
unsigned int VBO,VAO;
float vertices[] = {-0.5f,-0.5f,0.0f,0.5f,-0.5f,0.0f,0.0f,0.5f,0.0f
};
//顶点片段着色器
const char* vertexSharedSource = "#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";unsigned int shaderProgram ;
unsigned int vertexShader;
unsigned int fragmentShader;MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions(); //初始化OpenGL函数,将QT里的函数指针指向显卡的函数。//创建VBO和VAO对象,并赋予IDglGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);//绑定VBO和VAO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值//第0个属性里面3个值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO VBO 进行休息。glBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER,0);//顶点着色器vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader,1,&vertexSharedSource,NULL);glCompileShader(vertexShader);//片段着色器shaderfragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);glCompileShader(fragmentShader); //编译程序//进行链接程序shaderProgram = glCreateProgram();glAttachShader(shaderProgram,vertexShader);glAttachShader(shaderProgram,fragmentShader);glLinkProgram(shaderProgram);}void MyOpenGLWidget::resizeGL(int w, int h)
{}void MyOpenGLWidget::paintGL()
{//需要先初始化在使用glClearColor(0.2f,0.2f,0.2f,1.0f); //设置状态glClear(GL_COLOR_BUFFER_BIT); //使用状态glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES,0,3);glDeleteShader(vertexShader);glDeleteShader(fragmentShader);}

    索引缓冲对象

(Element Buffer Object ,EBO)也叫(Index Buffer Object,IBO)可以绘制两个三角形来组成一个矩形(OPenGL主要处理三角形)这会生成下面的顶点的集合。

#include "myopenglwidget.h"//创建VBO和VAO对象,并赋予ID
unsigned int VBO,VAO;float vertices[] = {//6个点为一个矩形0.5f,0.5f,0.0f,0.5f,-0.5f,0.0f,-0.5f,0.5f,0.0f,0.5f,-0.5f,0.0f,-0.5f,0.5f,0.0f,-0.5f,-0.5f,0.0f,
};//顶点片段着色器
const char* vertexSharedSource = "#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";unsigned int shaderProgram ;
unsigned int vertexShader;
unsigned int fragmentShader;MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions(); //初始化OpenGL函数,将QT里的函数指针指向显卡的函数。//创建VBO和VAO对象,并赋予IDglGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);//绑定VBO和VAO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值//第0个属性里面3个值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO VBO 进行休息。glBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER,0);//顶点着色器vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader,1,&vertexSharedSource,NULL);glCompileShader(vertexShader);//片段着色器shaderfragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);glCompileShader(fragmentShader); //编译程序//进行链接程序shaderProgram = glCreateProgram();glAttachShader(shaderProgram,vertexShader);glAttachShader(shaderProgram,fragmentShader);glLinkProgram(shaderProgram);}void MyOpenGLWidget::resizeGL(int w, int h)
{}void MyOpenGLWidget::paintGL()
{//需要先初始化在使用glClearColor(0.2f,0.2f,0.2f,1.0f); //设置状态glClear(GL_COLOR_BUFFER_BIT); //使用状态glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES,0,6);glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //用线条填充,查看边框glDeleteShader(vertexShader);glDeleteShader(fragmentShader);}

EBO画矩形

#include "myopenglwidget.h"//创建VBO和VAO对象,并赋予ID
unsigned int VBO,VAO,EBO;float vertices[] = {//6个点为一个矩形0.5f,0.5f,0.0f,0.5f,-0.5f,0.0f,-0.5f,0.5f,0.0f,
//    -0.5f,0.5f,0.0f,
//    0.5f,-0.5f,0.0f,-0.5f,-0.5f,0.0f,
};unsigned int indices[] = {0,1,2,1,2,3
};
//顶点片段着色器
const char* vertexSharedSource = "#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";unsigned int shaderProgram ;
unsigned int vertexShader;
unsigned int fragmentShader;MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions(); //初始化OpenGL函数,将QT里的函数指针指向显卡的函数。//创建VBO和VAO对象,并赋予IDglGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);//绑定VBO和VAO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值//第0个属性里面3个值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO VBO 进行休息。
//    glBindVertexArray(0); //解绑glBindBuffer(GL_ARRAY_BUFFER,0);//顶点着色器vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader,1,&vertexSharedSource,NULL);glCompileShader(vertexShader);//片段着色器shaderfragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);glCompileShader(fragmentShader); //编译程序//进行链接程序shaderProgram = glCreateProgram();glAttachShader(shaderProgram,vertexShader);glAttachShader(shaderProgram,fragmentShader);glLinkProgram(shaderProgram);//EBOglGenBuffers(1,&EBO);//绑定VBO和VAO对象glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);//EBO解绑,解绑之后数据会丢失
//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);}void MyOpenGLWidget::resizeGL(int w, int h)
{}void MyOpenGLWidget::paintGL()
{//需要先初始化在使用glClearColor(0.2f,0.2f,0.2f,1.0f); //设置状态glClear(GL_COLOR_BUFFER_BIT); //使用状态glUseProgram(shaderProgram);glBindVertexArray(VAO);
//    glDrawArrays(GL_TRIANGLES,0,6);
//    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //用线条填充,查看边框glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); //从索引里拿数据,可以直接用&indices,但是不能绑定在使用 也可以靠VAO监控EBOglDeleteShader(vertexShader);glDeleteShader(fragmentShader);}

练习

练习一

1.通过添加多个顶点数据,使用glDrawArrays绘制两个挨在一起的三角形

#include "myopenglwidget.h"//创建VBO和VAO对象,并赋予ID
unsigned int VBO,VAO,EBO;float vertices[] = {-0.9f,-0.5f,0.0f,-0.0f,-0.5f,0.0f,-0.45f,0.5f,0.0f,0.0f,-0.5f,0.0f,0.9f,-0.5f,0.0f,0.45f,0.5f,0.0f,};unsigned int indices[] = {0,1,2,1,2,3
};
//顶点片段着色器
const char* vertexSharedSource = "#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";unsigned int shaderProgram ;
unsigned int vertexShader;
unsigned int fragmentShader;MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions(); //初始化OpenGL函数,将QT里的函数指针指向显卡的函数。//创建VBO和VAO对象,并赋予IDglGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);//绑定VBO和VAO对象glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER,VBO);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值//第0个属性里面3个值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO VBO 进行休息。
//    glBindVertexArray(0); //解绑glBindBuffer(GL_ARRAY_BUFFER,0);//顶点着色器vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader,1,&vertexSharedSource,NULL);glCompileShader(vertexShader);//片段着色器shaderfragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);glCompileShader(fragmentShader); //编译程序//进行链接程序shaderProgram = glCreateProgram();glAttachShader(shaderProgram,vertexShader);glAttachShader(shaderProgram,fragmentShader);glLinkProgram(shaderProgram);//EBOglGenBuffers(1,&EBO);//绑定VBO和VAO对象glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);//EBO解绑,解绑之后数据会丢失
//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);}void MyOpenGLWidget::resizeGL(int w, int h)
{}void MyOpenGLWidget::paintGL()
{//需要先初始化在使用glClearColor(0.2f,0.2f,0.2f,1.0f); //设置状态glClear(GL_COLOR_BUFFER_BIT); //使用状态glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES,0,6);
//    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //用线条填充,查看边框//    glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); //从索引里拿数据,可以直接用&indices,但是不能绑定在使用 也可以靠VAO监控EBOglDeleteShader(vertexShader);glDeleteShader(fragmentShader);}

练习二

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

#include "myopenglwidget.h"//创建VBO和VAO对象,并赋予ID
unsigned int VBO[2],VAO[2],EBO;float firstTriangle[] = {-0.9f,-0.5f,0.0f,-0.0f,-0.5f,0.0f,-0.45f,0.5f,0.0f};float secondTriangle[] = {0.0f,-0.5f,0.0f,0.9f,-0.5f,0.0f,0.45f,0.5f,0.0f
};//顶点片段着色器
const char* vertexSharedSource = "#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";unsigned int shaderProgram ;
unsigned int vertexShader;
unsigned int fragmentShader;MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{}MyOpenGLWidget::~MyOpenGLWidget()
{glDeleteVertexArrays(2,VAO);
}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions(); //初始化OpenGL函数,将QT里的函数指针指向显卡的函数。//一次创建多个VBO和VAO对象glGenVertexArrays(2,VAO);glGenBuffers(2,VBO);//绑定VBO和VAO对象glBindVertexArray(VAO[0]);glBindBuffer(GL_ARRAY_BUFFER,VBO[0]);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(firstTriangle),firstTriangle,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值//第0个属性里面3个值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO[0]的第一个属性//绑定VBO和VAO对象glBindVertexArray(VAO[1]);glBindBuffer(GL_ARRAY_BUFFER,VBO[1]);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(secondTriangle),secondTriangle,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值//第0个属性里面3个值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO[1]的第一个属性//顶点着色器vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader,1,&vertexSharedSource,NULL);glCompileShader(vertexShader);//片段着色器shaderfragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);glCompileShader(fragmentShader); //编译程序//进行链接程序shaderProgram = glCreateProgram();glAttachShader(shaderProgram,vertexShader);glAttachShader(shaderProgram,fragmentShader);glLinkProgram(shaderProgram);//EBO
//    glGenBuffers(1,&EBO);//绑定VBO和VAO对象
//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
//    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);//EBO解绑,解绑之后数据会丢失
//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);}void MyOpenGLWidget::resizeGL(int w, int h)
{}void MyOpenGLWidget::paintGL()
{//需要先初始化在使用glClearColor(0.2f,0.2f,0.2f,1.0f); //设置状态glClear(GL_COLOR_BUFFER_BIT); //使用状态glUseProgram(shaderProgram);glBindVertexArray(VAO[0]);glDrawArrays(GL_TRIANGLES,0,3);glBindVertexArray(VAO[1]);glDrawArrays(GL_TRIANGLES,0,3);glDeleteShader(vertexShader);glDeleteShader(fragmentShader);}

练习三

创建两个着色器程序,其中一个使用片段着色器输出黄色

#include "myopenglwidget.h"//创建VBO和VAO对象,并赋予ID
unsigned int VBO[2],VAO[2],EBO;float firstTriangle[] = {-0.9f,-0.5f,0.0f,-0.0f,-0.5f,0.0f,-0.45f,0.5f,0.0f};float secondTriangle[] = {0.0f,-0.5f,0.0f,0.9f,-0.5f,0.0f,0.45f,0.5f,0.0f
};//顶点片段着色器
const char* vertexSharedSource = "#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";const char* fragmentShader2Source = "#version 330 core\n""out vec4 FragColor;\n""void main()\n""{\n""FragColor = vec4(1.0f,1.0f,0.0f,1.0f);\n }\n";unsigned int shaderProgram ,shaderProgram2;
unsigned int vertexShader;
unsigned int fragmentShader,fragmentShader2;MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{}MyOpenGLWidget::~MyOpenGLWidget()
{glDeleteVertexArrays(2,VAO);
}void MyOpenGLWidget::initializeGL()
{initializeOpenGLFunctions(); //初始化OpenGL函数,将QT里的函数指针指向显卡的函数。//一次创建多个VBO和VAO对象glGenVertexArrays(2,VAO);glGenBuffers(2,VBO);//绑定VBO和VAO对象glBindVertexArray(VAO[0]);glBindBuffer(GL_ARRAY_BUFFER,VBO[0]);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(firstTriangle),firstTriangle,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值//第0个属性里面3个值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO[0]的第一个属性//绑定VBO和VAO对象glBindVertexArray(VAO[1]);glBindBuffer(GL_ARRAY_BUFFER,VBO[1]);//为当前绑定到target的缓冲区对象创建一个新的数据存储//如果data不是NULL,则使用来自此指针的数据初始化数据存储glBufferData(GL_ARRAY_BUFFER,sizeof(secondTriangle),secondTriangle,GL_STATIC_DRAW);//告知显卡如何去解析缓冲区里的值//第0个属性里面3个值glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启VAO管理的第一个属性值。glEnableVertexAttribArray(0);//VAO[1]的第一个属性//顶点着色器vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader,1,&vertexSharedSource,NULL);glCompileShader(vertexShader);//片段着色器shaderfragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);glCompileShader(fragmentShader); //编译程序fragmentShader2 = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader2,1,&fragmentShader2Source,NULL);glCompileShader(fragmentShader2); //编译程序//进行链接程序shaderProgram = glCreateProgram();glAttachShader(shaderProgram,vertexShader);glAttachShader(shaderProgram,fragmentShader);glLinkProgram(shaderProgram);shaderProgram2 = glCreateProgram();glAttachShader(shaderProgram2,vertexShader);glAttachShader(shaderProgram2,fragmentShader2);glLinkProgram(shaderProgram2);//EBO
//    glGenBuffers(1,&EBO);//绑定VBO和VAO对象
//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
//    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);//EBO解绑,解绑之后数据会丢失
//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);}void MyOpenGLWidget::resizeGL(int w, int h)
{}void MyOpenGLWidget::paintGL()
{//需要先初始化在使用glClearColor(0.2f,0.2f,0.2f,1.0f); //设置状态glClear(GL_COLOR_BUFFER_BIT); //使用状态glUseProgram(shaderProgram);glBindVertexArray(VAO[0]);glDrawArrays(GL_TRIANGLES,0,3);glUseProgram(shaderProgram2);glBindVertexArray(VAO[1]);glDrawArrays(GL_TRIANGLES,0,3);glDeleteShader(vertexShader);glDeleteShader(fragmentShader);glDeleteShader(fragmentShader2);}

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

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

相关文章

基于生成对抗网络增强主动学习的超高温陶瓷硬度优化

复现论文:基于生成对抗网络增强主动学习的超高温陶瓷硬度优化 我将使用Python复现这篇关于使用生成对抗网络(GAN)增强主动学习来优化超高温陶瓷(UHTC)硬度的研究论文。以下是完整的实现代码和解释。 1. 环境准备和数据加载 首先,我们需要准备必要的Python库并加载数据。 …

hadoop(服务器伪分布式搭建)

1. 报错 Windows 上写的脚本 拷贝到 Linux&#xff08;比如 CentOS&#xff09;系统时会出现。 bash: ./set_java_home.sh: /bin/bash^M: bad interpreter: No such file or directory 报错原因 ^M 是 Windows 的换行符&#xff08;\r\n&#xff09; Linux 使用的是 Unix 格式的…

超详细 anji-captcha滑块验证springboot+uniapp微信小程序前后端组合

目录 1&#xff1a;pom文件引入jar包 2&#xff1a;配置文件 3&#xff1a;踩坑-1 4&#xff1a;踩坑-2 5&#xff1a;后端二次验证 6&#xff1a;自定义背景图 给用户做的一个小程序&#xff0c;被某局安全验证后&#xff0c;说登录太简单&#xff0c;没有验证码等行为认…

使用AVPlayer播放FairPlay DRM视频的最佳实践

01DRM 介绍DRM&#xff0c;即数字版权管理&#xff08;Digital Rights Management&#xff09;&#xff0c;是指使用加密技术保护视频内容、通过专业技术安全地存储和传输密钥&#xff08;加密密钥和解密密钥&#xff09;、并允许内容生产商设置商业规则&#xff0c;限制内容观…

《机器学习数学基础》补充资料:拉格朗日乘子法

瑞士数学家欧拉&#xff08;Leonhard Euler&#xff0c;1707-1783&#xff09;的大名&#xff0c;如雷贯耳——欧拉&#xff0c;是按德文发音翻译。欧拉不仅是公认的十八世纪最伟大的数学家&#xff0c;还是目前史上最多产的数学家。所著的书籍及论文多达 886 部&#xff08;篇…

【PTA数据结构 | C语言版】二叉堆的朴素建堆操作

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录题目代码题目 请编写程序&#xff0c;将 n 个顺序存储的数据用朴素建堆操作调整为最小堆&#xff1b;最后顺次输出堆中元素以检验操作的正确性。 输入格式&#xff1a; 输入首先给出一个正整数 c&#xff08;≤1…

深入解析PyQt5信号与槽的高级玩法:解锁GUI开发新姿势

信号与槽机制是PyQt框架实现组件间通信的核心技术。掌握其高级用法能极大提升开发效率和代码灵活性。本文将通过六大核心模块&#xff0c;结合实战案例&#xff0c;全方位解析信号与槽的进阶使用技巧。自定义信号与槽的完全指南 1. 信号定义规范 class CustomWidget(QWidget):#…

gitee某个分支合并到gitlab目标分支

一、克隆Gitee仓库到本地 git clone https://gitee.com/用户名/仓库名.gitcd 仓库名二、添加 GitLab 仓库作为远程仓库 git remote add gitlab https://gitlab.com/用户名/仓库名.git三、查看所有远程仓库 git remote -v四、拉取 Gitee 上的目标分支 git fetch origin 分支名五…

PyQt5信号与槽(信号与槽的高级玩法)

信号与槽的高级玩法 高级自定义信号与槽 所谓高级自定义信号与槽&#xff0c;指的是我们可以以自己喜欢的方式定义信号与槽函 数&#xff0c;并传递参数。自定义信号的一般流程如下&#xff1a; &#xff08;1&#xff09;定义信号。 &#xff08;2&#xff09;定义槽函数。 &a…

第5天 | openGauss中一个用户可以访问多个数据库

接着昨天继续学习openGauss,今天是第五天了。今天学习内容是使用一个用户访问多个数据库。 老规矩&#xff0c;先登陆墨天轮为我准备的实训实验室 rootmodb:~# su - omm ommmodb:~$ gsql -r创建表空间music_tbs、数据库musicdb10 、用户user10 并赋予 sysadmin权限 omm# CREATE…

Vue3 Anime.js超级炫酷的网页动画库详解

简介 Anime.js 是一个轻量级的 JavaScript 动画库&#xff0c;它提供了简单而强大的 API 来创建各种复杂的动画效果。以下是 Anime.js 的主要使用方法和特性&#xff1a; 安装 npm install animejs 基本用法 <script setup> import { ref, onMounted } from "vu…

苦练Python第18天:Python异常处理锦囊

苦练Python第18天&#xff1a;Python异常处理锦囊 原文链接&#xff1a;https://dev.to/therahul_gupta/day-18100-exception-handling-with-try-except-in-python-3m5a 作者&#xff1a;Rahul Gupta 译者&#xff1a;倔强青铜三 前言 大家好&#xff0c;我是倔强青铜三。是一名…

JVM——如何对java的垃圾回收机制调优?

GC 调优的核心思路就是尽可能的使对象在年轻代被回收&#xff0c;减少对象进入老年代。 具体调优还是得看场景根据 GC 日志具体分析&#xff0c;常见的需要关注的指标是 Young GC 和 Full GC 触发频率、原因、晋升的速率、老年代内存占用量等等。 比如发现频繁会产生 Ful GC&am…

正则表达式使用示例

下面以 Vue&#xff08;前端&#xff09;和 Spring Boot&#xff08;后端&#xff09;为例&#xff0c;展示正则表达式在前后端交互中的应用&#xff0c;以邮箱格式验证为场景&#xff1a;1.前端<template><div class"register-container"><h3>用户…

云端微光,AI启航:低代码开发的智造未来

文章目录前言一、引言&#xff1a;技术浪潮中的个人视角初次体验腾讯云开发 Copilot1.1 低代码的时代机遇1.1.1 为什么低代码如此重要&#xff1f;1.2 AI 的引入&#xff1a;革新的力量1.1.2 Copilot 的亮点1.3 初学者的视角1.3.1 Copilot 带来的改变二、体验记录&#xff1a;云…

图片上传实现

图片上传change函数图片上传图片上传到服务器上传的图片在该页面中显示修改界面代码最终实现效果change函数 这里我们先用输入框控件来举例&#xff1a; 姓名&#xff1a;<input typetext classname>下面我们来写 js 语句&#xff0c;对控件进行绑事件来获取输入框内的…

【PTA数据结构 | C语言版】多叉堆的上下调整

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录题目代码题目 请编写程序&#xff0c;将 n 个已经满足 d 叉最小堆顺序约束的数据直接读入最小堆&#xff1b;随后将下一个读入的数据 x 插入堆&#xff1b;再执行删顶操作并输出删顶的元素&#xff1b;最后顺次输…

selenium后续!!

小项目案例:实现批量下载网页中的资源根据15.3.2小节中的返回网页内容可知,用户只有获取了网页中的图片url才可以将图片下载到*在使用selenium库渲染网页后,可直接通过正则表达式过滤出指定的网页图片&#xff0c;从而实现批量下载接下来以此为思路来实现一个小项目案例。项目任…

深度解析Linux文件I/O三级缓冲体系:用户缓冲区→标准I/O→内核页缓存

在Linux文件I/O操作中&#xff0c;缓冲区的管理是一个核心概念&#xff0c;主要涉及用户空间缓冲区和内核空间缓冲区。理解这两者的区别和工作原理对于高效的文件操作至关重要。 目录 一、什么是缓冲区 二、为什么要引入缓冲区机制 三、三级缓冲体系 1、三级缓冲体系全景图…

【每日算法】专题十三_队列 + 宽搜(bfs)

1. 算法思路 BFS 算法核心思路 BFS&#xff08;广度优先搜索&#xff09;使用 队列&#xff08;Queue&#xff09;按层级顺序遍历图或树的节点。以下是 C 实现的核心思路和代码模板&#xff1a; 算法框架 #include <queue> #include <vector> #include <un…