vert
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}
frag
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
//混合两个纹理,最后一个值是两者的比例,越大后者越明显
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.8);
}
.h
#pragma once
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
class CoreFunctionWidget : public QOpenGLWidget
, protected /*QOpenGLExtraFunctions*/QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
explicit CoreFunctionWidget(QWidget *parent = nullptr);
~CoreFunctionWidget();
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
private:
QOpenGLShaderProgram shaderProgram;
};
.cpp
#include "CoreFunctionWidget.h"
#include <QDebug>
#include <QTimer>
//EBO是索引缓存对象
static GLuint VBO, VAO, EBO, texture1, texture2;
CoreFunctionWidget::CoreFunctionWidget(QWidget *parent) : QOpenGLWidget(parent)
{
}
CoreFunctionWidget::~CoreFunctionWidget()
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
}
void CoreFunctionWidget::initializeGL() {
this->initializeOpenGLFunctions();
bool success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "textures.vert");
if (!success) {
qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log();
return;
}
success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "textures.frag");
if (!success) {
qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log();
return;
}
success = shaderProgram.link();
if (!success) {
qDebug() << "shaderProgram link failed!" << shaderProgram.log();
}
//VAO,VBO data
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
};
//索引数组
unsigned int indices[] = {
0, 1, 2, // 第一个三角形
2, 3, 0// 第二个三角形
};
//生成三个对象
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
//绑定VAO
glBindVertexArray(VAO);
//绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//绑定EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 位置
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);//开启0号位置的数组计算
// 颜色
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// 纹理
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
//第一个纹理
glGenTextures(1, &texture1);//生成纹理
glBindTexture(GL_TEXTURE_2D, texture1);//绑定纹理,指定为2D
// 设置纹理的环绕参数
//第二个参数需要我们指定设置的选项与应用的纹理轴。配置的是WRAP选项,并且指定S和T轴
//第三个参数
//GL_REPEAT 对纹理的默认行为。重复纹理图像
//GL_MIRRORED_REPEAT和GL_REPEAT一样,但每次重复图片是镜像放置的。
//GL_CLAMP_TO_EDGE 纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。
//GL_CLAMP_TO_BORDER 超出的坐标为用户指定的边缘颜色。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 设置纹理的过滤参数
//当进行放大(Magnify)和缩小(Minify)操作的时候可以设置纹理过滤的选项,
//比如你可以在纹理被缩小的时候使用邻近过滤,被放大时使用线性过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//载入jpg图片
QImage img1 = QImage("container.jpg").convertToFormat(QImage::Format_RGB888);
if (!img1.isNull()) {
/* GLenum target 指定活动纹理单元的目标纹理
GLint level 指定细节级别,0级表示基本图像,n级则表示Mipmap缩小n级之后的图像(缩小2^n)
GLint internalformat 指定纹理内部格式
GLsizei width
GLsizei height 指定纹理图像的宽高
GLint border 指定边框的宽度。必须为0
GLenum format 指定纹理数据的格式。必须匹配internalformat下面的符号值被接受:GL_ALPHA,GL_RGB,GL_RGBA,GL_LUMINANCE,和GL_LUMINANCE_ALPHA。
GLenum type 指定纹理数据的数据类型
const GLvoid * data 指定一个指向内存中图像数据的指针
*/
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img1.width(), img1.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, img1.bits());
glGenerateMipmap(GL_TEXTURE_2D);//生成纹理
}
// 第二个纹理
// ---------
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
QImage img2 = QImage("awesomeface.png").convertToFormat(QImage::Format_RGBA8888).mirrored(false,true);//通常需要这样翻转图片
if (!img2.isNull()) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img2.width(), img2.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img2.bits());
glGenerateMipmap(GL_TEXTURE_2D);//生成纹理
}
//启用着色器
shaderProgram.bind();
glUniform1i(shaderProgram.uniformLocation("texture1"), 0);
glUniform1i(shaderProgram.uniformLocation("texture2"), 1);
shaderProgram.release();
}
void CoreFunctionWidget::resizeGL(int w, int h) {
glViewport(0, 0, w, h);
}
void CoreFunctionWidget::paintGL() {
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shaderProgram.bind();
{
glActiveTexture(GL_TEXTURE0);//激活第一个纹理
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);//激活第二个纹理 (最多可以有32个纹理)
glBindTexture(GL_TEXTURE_2D, texture2);
//绑定VAO
glBindVertexArray(VAO);
//根据索引画
/*
mode 指定要渲染的图元类型。 接受符号常量GL_POINTS,GL_LINE_STRIP,GL_LINE_LOOP,GL_LINES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN和GL_TRIANGLES。
count 指定要渲染的元素数。
type 指定indices中值的类型。 必须是GL_UNSIGNED_BYTE或GL_UNSIGNED_SHORT。
indices 指定指向存储索引的位置的指针。
*/
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
shaderProgram.release();
}
![](https://i-blog.csdnimg.cn/blog_migrate/0a22f6a63e4b50e0475a59945175f2bd.png)