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对象,并赋予ID
glGenVertexArrays(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对象,并赋予ID
glGenVertexArrays(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);
//片段着色器shader
fragmentShader = 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对象,并赋予ID
glGenVertexArrays(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);
//片段着色器shader
fragmentShader = 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对象,并赋予ID
glGenVertexArrays(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);
//片段着色器shader
fragmentShader = 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);
// glDrawArrays(GL_TRIANGLES,0,6);
// glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //用线条填充,查看边框
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); //从索引里拿数据,可以直接用&indices,但是不能绑定在使用 也可以靠VAO监控EBO
glDeleteShader(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对象,并赋予ID
glGenVertexArrays(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);
//片段着色器shader
fragmentShader = 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);
glDrawArrays(GL_TRIANGLES,0,6);
// glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //用线条填充,查看边框
// glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0); //从索引里拿数据,可以直接用&indices,但是不能绑定在使用 也可以靠VAO监控EBO
glDeleteShader(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);
//片段着色器shader
fragmentShader = 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);
//片段着色器shader
fragmentShader = 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);
}