本篇文章的复现对应于LearnOpenGL教程的入门纹理教程。
使用OpenGL时经常需要在画面中显示2D的图像或是给3D的图形表面贴一张2D的图像,这个时候就会用到纹理贴图。具体的细节LearnOpenGL教程已经讲得很清楚了,这里就不再赘述。
不过,有一点比较神奇也可以说是反直觉的地方需要注意一下。在以前的认知中,图像一般要放在一个矩形框中进行显示,很多时候我们用QT或者MFC等界面库的时候也的确就是这么操作的。然而在OpenGL或者Direct这种渲染框架中贴图不是这样的,由于空间中3个点就能确定一个平面,因此为了空间精细度,我们贴图在大部分情况下是贴在三角形上的。
具体的实现本人已经转到Qt下了,代码如下:
MyOpenGLWidget.h
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLShaderProgram>
#include <QElapsedTimer>
#include <QOpenGLTexture>
#include <QDebug>
class MyOpenGLWidget : public QOpenGLWidget
{
Q_OBJECT
public:
MyOpenGLWidget(QWidget *partent);
~MyOpenGLWidget();
protected:
void initializeGL();//初始化函数,在Widget刚加载时被调用
void paintGL();//绘图函数,每一次绘图请求产生,都会进行一次绘图
void resizeGL(int w, int h);//用于处理窗口大小变化的情况
private:
QOpenGLBuffer *m_vbo,*m_ebo;
QOpenGLVertexArrayObject *m_vao;
QOpenGLShaderProgram *m_shader;//渲染器程序对象
QOpenGLFunctions *f;//OpenGL函数对象
QOpenGLTexture *texture1 = nullptr;
QOpenGLTexture *texture2 = nullptr;
};
#endif // MYOPENGLWIDGET_H
MyOpenGLWidget.cpp
#include <MyOpenGLWidget.h>
MyOpenGLWidget::MyOpenGLWidget(QWidget* parent):
QOpenGLWidget (parent)
{
}
MyOpenGLWidget::~MyOpenGLWidget()
{
//多线程调用保护
makeCurrent();
//对象释放
m_vbo->destroy();
m_ebo->destroy();
m_vao->destroy();
delete texture1;
delete texture2;
//退出保护
doneCurrent();
}
void MyOpenGLWidget::initializeGL()
{
f = this->context()->functions();
f->glEnable(GL_DEPTH_TEST); // 三维绘图的关键!
m_shader = new QOpenGLShaderProgram();
m_shader->addShaderFromSourceFile(QOpenGLShader::Vertex, "../Demo1/Vertex.vert");
m_shader->addShaderFromSourceFile(QOpenGLShader::Fragment, "../Demo1/Fragment.frag");
if (m_shader->link()) {
qDebug("Shaders link success.");
} else {
qDebug("Shaders link failed!");
}
//VBO,VEO数据
static const GLfloat vertices[] = {
//位置 //颜色 //纹理位置
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
static const GLint indices[] = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
m_vao = new QOpenGLVertexArrayObject();
m_vbo = new QOpenGLBuffer(QOpenGLBuffer::Type::VertexBuffer);
m_ebo = new QOpenGLBuffer(QOpenGLBuffer::Type::IndexBuffer);
m_vao->create();
m_vao->bind();
m_vbo->create();
m_vbo->bind();
m_vbo->allocate(vertices, 4*8*sizeof(GLfloat));
m_ebo->create();
m_ebo->bind();
m_ebo->allocate(indices, 2*3*sizeof(GLint));
int attr = -1;
//顶点属性设置
attr = m_shader->attributeLocation("aPos");
m_shader->setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 8);
m_shader->enableAttributeArray(attr);
//颜色属性设置
attr = m_shader->attributeLocation("aColor");
m_shader->setAttributeBuffer(attr, GL_FLOAT, sizeof(GLfloat) * 3, 3, sizeof(GLfloat) * 8);
m_shader->enableAttributeArray(attr);
//纹理属性设置
attr = m_shader->attributeLocation("aTexCoord");
m_shader->setAttributeBuffer(attr, GL_FLOAT, sizeof(GLfloat) * 6, 2, sizeof(GLfloat) * 8);
m_shader->enableAttributeArray(attr);
m_vao->release();
m_vbo->release();
m_ebo->release();
//纹理读取
// texture 1
texture1 = new QOpenGLTexture(QImage("container.jpg"), QOpenGLTexture::GenerateMipMaps);//直接生成绑定一个2d纹理, 并生成多级纹理MipMaps
if(!texture1->isCreated()){
qDebug() << "Failed to load texture";
}
//设置纹理对象的环绕
texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//设置纹理对象的采样方式
texture1->setMinificationFilter(QOpenGLTexture::Linear);//缩小
texture1->setMagnificationFilter(QOpenGLTexture::Linear);//放大
// texture 2
texture2 = new QOpenGLTexture(QImage("1.jpeg"), QOpenGLTexture::GenerateMipMaps);
if(!texture2->isCreated()){
qDebug() << "Failed to load texture";
}
texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
texture2->setMinificationFilter(QOpenGLTexture::Linear);
texture2->setMagnificationFilter(QOpenGLTexture::Linear);
//设置纹理对应的单元
m_shader->bind();
m_shader->setUniformValue("texture1", 0);
m_shader->setUniformValue("texture2", 1);
m_shader->release();
}
void MyOpenGLWidget::paintGL()
{
//纹理绑定
f->glActiveTexture(GL_TEXTURE0);
texture1->bind();
f->glActiveTexture(GL_TEXTURE1);
texture2->bind();
f->glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
f->glClearColor(0.0f, 0.2f, 0.0f, 1.0f);
m_vao->bind();
m_shader->bind();
f->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);//绘制索引对象
m_shader->release();
m_vao->release();
texture1->release();
texture2->release();
}
void MyOpenGLWidget::resizeGL(int w, int h)
{
f->glViewport(0, 0, w, h);
}