写在开头:文章是基于纹理 - LearnOpenGL CN 教程的学习记录,强烈建议在网站上先弄清楚原理再看此文章。以Qt-GL窗口代替GLFW的写法,Qt库中一些类代替教程中的类,一起入坑。
效果图:
上图使用了两纹理混合。接下来是一些比较重要的,使用glUniform1i,可以给纹理采样器分配一个位置值,这样的话我们能够在一个片段着色器中设置多个纹理。一个纹理的位置值通常称为一个纹理单元(Texture Unit)。一个纹理的默认纹理单元是0,它是默认的激活纹理单元,所以教程前面部分我们没有分配一个位置值。
纹理单元的主要目的是让我们在着色器中可以使用多于一个的纹理。通过把纹理单元赋值给采样器,我们可以一次绑定多个纹理,只要我们首先激活对应的纹理单元。就像glBindTexture一样,我们可以使用glActiveTexture激活纹理单元,传入我们需要使用的纹理单元:
如果有需要更多的纹理应当这样:
//激活纹理单元0
glActiveTexture(GL_TEXTURE0);
m_combine_texture1->bind();
//激活纹理单元1
glActiveTexture(GL_TEXTURE1);
m_combine_texture2->bind();
OpenGL至少保证有16个纹理单元供你使用,也就是说你可以激活从GL_TEXTURE0到GL_TEXTRUE15。它们都是按顺序定义的,所以我们也可以通过GL_TEXTURE0 + 8的方式获得GL_TEXTURE8,这在当我们需要循环一些纹理单元的时候会很有用.
不同于教程的地方:
用QOpenGLTexture代替stb_image.h
stb_image.h的写法:
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// load image, create texture and generate mipmaps
data = stbi_load(FileSystem::getPath("resources/textures/awesomeface.png").c_str(), &width, &height, &nrChannels, 0);
if (data)
{
// note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load texture" << std::endl;
}
QOpenGLTexture的写法:
m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());
if(!m_combine_texture2->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);
主要代码:
#ifndef TEXTUREWIDGET_H
#define TEXTUREWIDGET_H
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QDebug>
#include <QOpenGLTexture>
#include "Shader.h"
class HelloTexture;
namespace Ui {
class TextureWidget;
class QOpenGLTexture;
}
class TextureWidget : public QWidget
{
Q_OBJECT
public:
explicit TextureWidget(QWidget *parent = nullptr);
~TextureWidget();
private:
Ui::TextureWidget *ui;
HelloTexture *m_contentWidget;
};
class HelloTexture : public QOpenGLWidget,protected QOpenGLExtraFunctions
{
enum TARGET_STATUS
{
Original,
Combine,
Exercise2,
Exercise3,
Exercise4
};
public:
HelloTexture();
~HelloTexture();
private:
void InitOriginal();
void InitCombine();
void InitExercise2();
void InitExercise3();
void InitExercise4();
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
private:
TARGET_STATUS m_status;
Shader *m_shader;
QOpenGLTexture *m_texture;
QOpenGLTexture *m_combine_texture1;
QOpenGLTexture *m_combine_texture2;
};
#endif // TEXTUREWIDGET_H
cpp
#include "texturewidget.h"
#include "ui_texturewidget.h"
#include <QImage>
TextureWidget::TextureWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::TextureWidget)
{
ui->setupUi(this);
m_contentWidget = new HelloTexture();
ui->verticalLayout->addWidget(m_contentWidget);
}
TextureWidget::~TextureWidget()
{
delete ui;
}
static GLuint VBO, VAO, EBO = 0;
HelloTexture::HelloTexture()
{
}
HelloTexture::~HelloTexture()
{
}
void HelloTexture::InitOriginal()
{
m_status = TARGET_STATUS::Original;
m_shader = new Shader(":/shader/res/shaders/getting_started/4.1.texture.vs"
,":/shader/res/shaders/getting_started/4.1.texture.fs");
//垂直镜像mirrored
m_texture = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());
if(!m_texture->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_texture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_texture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_texture->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_texture->setMagnificationFilter(QOpenGLTexture::Linear);
//m_texture->setFormat(QOpenGLTexture::RGBFormat); //将纹理储存为rgb值
}
void HelloTexture::InitCombine()
{
m_status = TARGET_STATUS::Combine;
m_shader = new Shader(":/shader/res/shaders/getting_started/4.2.texture.vs"
,":/shader/res/shaders/getting_started/4.2.texture.fs");
//垂直镜像mirrored
m_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());
if(!m_combine_texture1->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_combine_texture1->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Linear);
m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());
if(!m_combine_texture2->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);
//设置纹理单元编号
m_shader->use();
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);
}
void HelloTexture::InitExercise2()
{
m_status = TARGET_STATUS::Exercise2;
m_shader = new Shader(":/shader/res/shaders/getting_started/4.3.texture.vs"
,":/shader/res/shaders/getting_started/4.3.texture.fs");
//垂直镜像mirrored
m_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());
if(!m_combine_texture1->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_combine_texture1->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Linear);
m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());
if(!m_combine_texture2->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);
//设置纹理单元编号
m_shader->use();
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);
}
void HelloTexture::InitExercise3()
{
m_status = TARGET_STATUS::Exercise3;
m_shader = new Shader(":/shader/res/shaders/getting_started/4.4.texture.vs"
,":/shader/res/shaders/getting_started/4.4.texture.fs");
//垂直镜像mirrored
m_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());
if(!m_combine_texture1->isCreated()){
qDebug() << "Failed to load texture";
}
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
m_combine_texture1->setMinificationFilter(QOpenGLTexture::Nearest);
m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Nearest);
m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());
if(!m_combine_texture2->isCreated()){
qDebug() << "Failed to load texture";
}
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
m_combine_texture2->setMinificationFilter(QOpenGLTexture::Nearest);
m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Nearest);
//设置纹理单元编号
m_shader->use();
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);
}
void HelloTexture::InitExercise4()
{
m_status = TARGET_STATUS::Exercise4;
m_shader = new Shader(":/shader/res/shaders/getting_started/4.5.texture.vs"
,":/shader/res/shaders/getting_started/4.5.texture.fs");
//垂直镜像mirrored
m_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());
if(!m_combine_texture1->isCreated()){
qDebug() << "Failed to load texture";
}
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
m_combine_texture1->setMinificationFilter(QOpenGLTexture::Linear);
m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Linear);
m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());
if(!m_combine_texture2->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);
//设置纹理单元编号
m_shader->use();
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);
//设置混合值
m_shader->m_shaderProgram.setUniformValue("mixValue", 0.5f);
}
void HelloTexture::initializeGL()
{
//初始化functions
this->initializeOpenGLFunctions();
//运行选项
//InitOriginal();
//InitCombine();
//InitExercise2();
//InitExercise3();
InitExercise4();
float ver[32];
if(m_status == Exercise2)
{
float vertices[] = {
// positions // colors // texture coords (note that we changed them to 2.0f!)
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 2.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, 2.0f // top left
};
for(int i = 0 ; i < 32; i++)
{
ver[i] = vertices[i];
}
}
else if(m_status == Exercise3)
{
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.55f, 0.55f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.55f, 0.45f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.45f, 0.45f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.45f, 0.55f // top left
};
for(int i = 0 ; i < 32; i++)
{
ver[i] = vertices[i];
}
}
else
{
float vertices[] = {
// positions // colors // texture coords
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
};
for(int i = 0 ; i < 32; i++)
{
ver[i] = vertices[i];
}
}
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(ver), ver, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
}
void HelloTexture::resizeGL(int w, int h)
{
glViewport(0,0,w,h);
}
void HelloTexture::paintGL()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if(m_status == Original)
{
m_texture->bind();
}else
{
//激活纹理单元0
glActiveTexture(GL_TEXTURE0);
m_combine_texture1->bind();
//激活纹理单元1
glActiveTexture(GL_TEXTURE1);
m_combine_texture2->bind();
}
// render container
m_shader->use();
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
下一篇:Qt-OpenGL-04 变换Transformations