一、更改笑脸朝向
题目:修改片段着色器,仅让笑脸图案朝另一个方向看。
更改片段着色器代码如下:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 ourTexture; //纹理坐标
uniform sampler2D textureWall; //第0个采样器
uniform sampler2D textureSmile; //第1个采样器
uniform sampler2D textureSmall; //第2个采样器
void main()
{
FragColor = mix(texture(textureWall, ourTexture),
texture(textureSmile, vec2(-ourTexture.x, ourTexture.y)), 0.5);
}
在paintGL函数中激活纹理单元
void MyOpenGLWidget::paintGL()
{
//设置墨绿色背景
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //状态设置
glClear(GL_COLOR_BUFFER_BIT); //状态使用
//绘制
m_shaderProgram.bind(); //激活程序对象
glBindVertexArray(VAO); //绑定VAO
m_textureWall->bind(0); //绑定激活纹理单元0
m_textureSmile->bind(1); //绑定激活纹理单元1
m_textureSmall->bind(2); //绑定激活纹理单元2
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL); //绘图
}
运行结果如下:
二、纹理环绕方式
题目:尝试用不同的纹理环绕方式,设定一个从0.0f到2.0f范围内的(而不是原来的0.0f到1.0f)纹理坐标。试试看能不能在箱子的角落放置4个笑脸。
更改顶点数据:
//顶点数据
float vertices[] = {
//位置 //颜色 //纹理
0.9f, 0.9f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, //右上角
0.9f, -0.9f, 0.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, //右下角
-0.9f, -0.9f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, //左下角
-0.9f, 0.9f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 2.0f //左上角
};
给glTexParameteri()函数传不同的参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
三、GL_NEAREST
题目:尝试在矩形上只显示纹理图像的中间一部分,修改纹理坐标,达到能看见单个的像素的效果。尝试使用GL_NEAREST的纹理过滤方式让像素显示得更清晰。
更改顶点数据:
//顶点数据
float vertices[] = {
//位置 //颜色 //纹理
0.9f, 0.9f, 0.0f, 1.0f, 0.0f, 0.0f, 0.55f, 0.55f, //右上角
0.9f, -0.9f, 0.0f, 0.0f, 1.0f, 0.0f, 0.55f, 0.45f, //右下角
-0.9f, -0.9f, 0.0f, 0.0f, 0.0f, 1.0f, 0.45f, 0.45f, //左下角
-0.9f, 0.9f, 0.0f, 1.0f, 1.0f, 0.0f, 0.45f, 0.55f //左上角
};
更改initializeGL()函数代码
m_textureSmile->bind(1);
//纹理环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
四、纹理可见度
题目:使用一个uniform变量作为mix函数的第三个参数来改变两个纹理可见度,使用上和下键来改变箱子或笑脸的可见度。
更改着色器程序,创建一个变量mixValue,用来接收纹理可见度
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 ourTexture; //纹理坐标
uniform sampler2D textureWall; //第0个采样器
uniform sampler2D textureSmile; //第1个采样器
uniform sampler2D textureSmall; //第2个采样器
uniform float mixValue;
void main()
{
FragColor = mix(texture(textureWall, ourTexture),
texture(textureSmile, vec2(-ourTexture.x, ourTexture.y)), mixValue);
}
更改myopenglwidget.h代码,创建接收鼠标事件函数keyPressEvent和纹理可见度变量mixValue
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
explicit MyOpenGLWidget(QWidget *parent = nullptr);
~MyOpenGLWidget();
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
void keyPressEvent(QKeyEvent *event);
private:
QOpenGLShaderProgram m_shaderProgram;
QOpenGLTexture *m_textureWall;
QOpenGLTexture *m_textureSmile;
QOpenGLTexture *m_textureSmall;
float mixValue = 0.5;
};
#endif // MYOPENGLWIDGET_H
更改myopenglwidget.cpp代码
#include "myopenglwidget.h"
#include <QDebug>
#include <QKeyEvent>
unsigned int VBO; //顶点缓冲对象
unsigned int VAO; //顶点数组对象
unsigned int EBO; //元素缓冲对象
MyOpenGLWidget::MyOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{
setFocusPolicy(Qt::StrongFocus);
}
MyOpenGLWidget::~MyOpenGLWidget()
{
makeCurrent();
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &EBO);
doneCurrent();
}
void MyOpenGLWidget::initializeGL()
{
//初始化OpenGL函数
initializeOpenGLFunctions();
//创建VBO,并赋予ID
glGenBuffers(1, &VBO);
//绑定VBO对象
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//顶点数据
float vertices[] = {
//位置 //颜色 //纹理
0.9f, 0.9f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, //右上角
0.9f, -0.9f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //右下角
-0.9f, -0.9f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, //左下角
-0.9f, 0.9f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f //左上角
};
//把顶点数据复制到显存中
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//创建VAO对象,并赋予ID
glGenVertexArrays(1, &VAO);
//绑定VAO对象
glBindVertexArray(VAO);
//创建EBO对象,并赋予ID
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
unsigned int indices[] = {
0, 1, 3, //第一个三角形
1, 2, 3 //第二个三角形
};
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); //开启VAO管理的第一个属性值
//颜色属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1); //开启VAO管理的第二个属性值
//纹理属性
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2); //开启VAO管理的第三个属性值
//解绑VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
//解绑VAO
glBindVertexArray(0);
//创建一个程序对象
m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/shapes.vert");
m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/shapes.frag");
bool success = m_shaderProgram.link();
if(!success)
qDebug()<<"ERR:" << m_shaderProgram.log();
m_shaderProgram.bind();
m_shaderProgram.setUniformValue("vertexColor", 0.0, 1.0, 0.0, 1.0);
m_textureWall = new QOpenGLTexture(QImage(":/images/wall.jpg").mirrored()); //mirrored消除镜像
m_shaderProgram.setUniformValue("textureWall", 0); //把纹理单元传给片段着色器中的采样器
m_textureSmile = new QOpenGLTexture(QImage(":/images/awesomeface.png").mirrored()); //mirrored消除镜像
m_shaderProgram.setUniformValue("textureSmile", 1); //把纹理单元传给片段着色器中的采样器
m_textureSmall = new QOpenGLTexture(QImage(":/images/small.png").mirrored()); //mirrored消除镜像
m_shaderProgram.setUniformValue("textureSmall", 2); //把纹理单元传给片段着色器中的采样器
m_shaderProgram.setUniformValue("mixValue", mixValue);
}
void MyOpenGLWidget::resizeGL(int w, int h)
{
Q_UNUSED(w);
Q_UNUSED(h);
//glViewport(0, 0, w, h);
}
void MyOpenGLWidget::paintGL()
{
//设置墨绿色背景
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //状态设置
glClear(GL_COLOR_BUFFER_BIT); //状态使用
//绘制
m_shaderProgram.bind(); //激活程序对象
glBindVertexArray(VAO); //绑定VAO
m_textureWall->bind(0); //绑定激活纹理单元0
m_textureSmile->bind(1); //绑定激活纹理单元1
m_textureSmall->bind(2); //绑定激活纹理单元2
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL); //绘图
}
void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Up)
mixValue+=0.1;
else if(event->key() == Qt::Key_Down)
mixValue-=0.1;
else
return;
if(mixValue > 1.0)
mixValue = 1.0;
if(mixValue < 0.0)
mixValue = 0.0;
makeCurrent();
m_shaderProgram.setUniformValue("mixValue", mixValue);
doneCurrent();
update();
QOpenGLWidget::keyPressEvent(event);
}
在函数initializeGL()最后一行给片段着色器中的mixValue变量设置一个初始值
m_shaderProgram.setUniformValue("mixValue", mixValue);
keyPressEvent函数接收键盘事件,当是上键时mixValue值+0.1,下键时-0.1,且维持mixValue值在0.0到1.0之间;
在自定义函数中修改GUP的值之前需要调用makeCurrent()函数,更改数值后调用doneCurrent()函数,之后调用update()函数进行界面更新,会自动调用paintGL()函数
makeCurrent();
m_shaderProgram.setUniformValue("mixValue", mixValue);
doneCurrent();
update();
运行结果如下:
通过摁上键或下键改变纹理可见度的值
注:观看OpenGL中文官网(https://learnopengl-cn.github.io/)和阿西拜的现代OpenGL入门(https://ke.qq.com/course/3999604#term_id=104150693)学习OpenGL