索引缓存器
当绘制一些联系的图形的时候,通常有一些点是连续的,可以被重复使用的点。比如重合的点,我只要在内存中定义一次,然后在显卡缓存中的可以重复使用,只要告诉数据的位置即可。这里就用到了索引缓存器(EBO)。
这里需要注意两点:首先需要配置好VBO,然后才能使用EBO
代码如下:
#pragma once
#include <QOpenGLWindow>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
class QOpenGLFunctions_3_3_Core;
//索引缓存对象的使用
class EBOWnd : public QOpenGLWindow{
Q_OBJECT
public:
EBOWnd();
~EBOWnd();
void initializeGL()override;
void resizeGL(int w, int h)override;
void paintGL()override;
private:
QOpenGLFunctions_3_3_Core* _openGLCore;
GLuint _EBO;
GLuint _VBO;
GLuint _VAO;
QOpenGLShaderProgram _shaderProgram;//着色器程序,所里系统所有的着色器
};
#include "EBOWnd.h"
#include <QOpenGLFunctions_3_3_Core>
EBOWnd::EBOWnd(){
}
EBOWnd::~EBOWnd(){
}
void EBOWnd::initializeGL() {
_openGLCore = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
/*
** 首先把所有图形的点按照一定的顺序列出来,然后在列一个索引表,指明哪些数据是一组
*/
GLfloat ver[] = {
0.5f, 0.5f, 0.0f, //第一象限
0.5f, -0.5f, 0.0f, //第四象限
-0.5f, -0.5f, 0.0f, //第三象限
-0.5f, 0.5f, 0.0f, //第二象限
};
GLuint idexVer[] = {
0, 1, 2, //数组中的第0/1/2三个点组成第一个三角形
1, 2, 3 //第1/2/3组成第二个三角形
};
//创建VAO,用来记录各种数据属性
_openGLCore->glGenVertexArrays(1, &_VAO);
//绑定VAO
_openGLCore->glBindVertexArray(_VAO);
//创建EBO VBO
_openGLCore->glGenBuffers(1, &_EBO);
_openGLCore->glGenBuffers(1, &_VBO);
//绑定EBO VBO
_openGLCore->glBindBuffer(GL_ARRAY_BUFFER, _VBO);
_openGLCore->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO);
//传送数据
_openGLCore->glBufferData(GL_ARRAY_BUFFER, sizeof(ver), ver, GL_STATIC_DRAW);
_openGLCore->glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idexVer), idexVer, GL_STATIC_DRAW);
/*
** 对VBO进行属性配置
*/
_openGLCore->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
//启用着色器
_openGLCore->glEnableVertexAttribArray(0);
//解绑VAO
_openGLCore->glBindVertexArray(0);
//解绑VBO
_openGLCore->glBindBuffer(GL_ARRAY_BUFFER, 0);
//解绑EBO
_openGLCore->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
/*
** 着色器
** 着色器属于动态编译
*/
QOpenGLShader vertexShager(QOpenGLShader::Vertex);//顶点着色器
vertexShager.compileSourceFile("E:/Projects/QtGuiTest/OPenGLApp/shader/triangle.vert");
QOpenGLShader fragmentShager(QOpenGLShader::Fragment);//片段着色器
fragmentShager.compileSourceFile("E:/Projects/QtGuiTest/OPenGLApp/shader/triangle.frag");
_shaderProgram.addShader(&vertexShager);
_shaderProgram.addShader(&fragmentShager);
_shaderProgram.link();
}
void EBOWnd::resizeGL(int w, int h) {
}
void EBOWnd::paintGL() {
//设置清除颜色,使用当前颜色,清除背景
_openGLCore->glClearColor(0.6f, 0.6f, 0.6f, 1.0f);
_openGLCore->glClear(GL_COLOR_BUFFER_BIT);
//把着色器送入显卡缓存
_shaderProgram.bind();
_openGLCore->glBindVertexArray(_VAO);//会将它记忆的那些状态,相当于那几个函数执行一遍
/*
** 第一个参数:绘制类型 三角形
** 第二个参数:绘制点数,两三角形就是6个点
** 第三个参数:数据类型,索引的值的类型 idexVer 为无符号整形
** 第四个参数:设置为0
*/
_openGLCore->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
update();
}
运行结果:
线框模式
我们重新调整一下点索引数组的顺序
GLuint idexVer[] = {
0, 1, 2, //数组中的第0/1/2三个点组成第一个三角形,顺时针
2, 0, 3 //第1/2/3组成第二个三角形,逆时针
};
解绑VAO之前调用这个函数,可以看到
其中第一个参数有多个选项:
#define GL_FRONT 0x0404
#define GL_BACK 0x0405
#define GL_FRONT_AND_BACK 0x0408
分别是前、后、前和后。
那什么才是一个多边形的前和后呢?
在OpenGL中一个面的法向量,与绘制这个面时的点的顺序有关;
以屏幕为例,如果一个多边形的点是顺时针绘制的,则法向量的从屏幕向里的,如果是逆时针在法向量的方向是向外的。
符合右手定则。
法向量向外的称为前面,法向量向内的称为后面
_openGLCore->glPolygonMode(GL_BACK, GL_LINE);
可以看一下效果:
aaa