OpenGL中的最小图元是三角形,两个三角形组合便构成了正方形,空间中的六个正方形首尾组合便构成了正方体。在正方形表面贴上纹理便构成了带纹理的正方体。程序中通过添加定时器定时改变纹理的组合和正方体的位置便得到了旋转变化的立方体。通过引入按键事件可以通过外部输入改变相机位置。程序中通过wsad键来调整相机的位置。
立方体变化的程序源码如下:
opengl.h
#ifndef OPENGL_H
#define OPENGL_H
#include
#include
#include
#include
#include
#include
#include
#include
class openGL : public QGLWidget, protected QGLFunctions
{
Q_OBJECT
public:
openGL(QWidget *parent = 0);
~openGL();
protected:
void initializeGL(); //初始化OpenGL
void resizeGL(int w, int h); //调整oeenGL的显示窗口
void paintGL(); //绘制opengl图像
void keyPressEvent(QKeyEvent *e);//按键响应事件
private:
void InitShader();
void InitBuffer();
private:
QGLShaderProgram shader;
QGLBuffer* vertexBuffer;
QGLBuffer* indexBuffer;
QTimer* m_rotateTimer;
private slots:
void ChangeUniform();
};
#endif // OPENGL_H
opengl.cpp
#include "opengl.h"
//顶点着色器
QString vertexShaderSource =
"#version 330 core\n\
layout (location = 0) in vec3 aPos;\n\
layout (location = 1) in vec2 aTexCoord;\n\
out vec2 TexCoord;\n\
uniform mat4 model;\n\
uniform mat4 view;\n\
uniform mat4 projection;\n\
void main()\n\
{\n\
gl_Position = projection * view * model * vec4(aPos, 1.0f);\n\
TexCoord = vec2(aTexCoord.x, aTexCoord.y);\n\
}";
//片元着色器
QString fragmentShaderSource =
"#version 330 core\n\
out vec4 FragColor;\n\
in vec2 TexCoord;\n\
uniform float mixValue;\n\
uniform sampler2D texture1;\n\
uniform sampler2D texture2;\n\
void main()\n\
{\n\
FragColor = mix(texture(texture1, TexCoord),texture(texture2, TexCoord),mixValue);\n\
}";
//四方体的六个面的顶点坐标和对应的纹理坐标
float vertices[] = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
//六个立方体的位置
QVector3D cubePosition[] =
{
QVector3D(0.0f, 0.0f, 0.0f),
QVector3D(2.0f, 5.0f, -15.0f),
QVector3D(-1.5f, -2.2f, -2.5f),
QVector3D(-3.8f, -2.0f, -12.3f),
QVector3D(2.4f, -0.4f, -3.5f),
QVector3D(-1.3f, 1.0f, -1.5f)
};
const unsigned int SRC_WIDTH = 1920; //窗口的宽度
const unsigned int SRC_HEIGHT = 1080; //窗口的高度
GLuint textureID,textureID2; //纹理ID
bool directFlag = true; //纹理变化的方向标识
float stepSize = 5; //转动变化的步长
float mixValue = 0.2;
QVector3D cameraPos(0.0f, 0.0f, 3.0f); //相机的位置
QVector3D cameraFront(0.0f, 0.0f, -1.0f);//相机的目标位置
QVector3D cameraUp(0.0f, 1.0f, 0.0f); //相机向上轴的方向
openGL::openGL(QWidget *parent)
: QGLWidget(parent)
{
//旋转的定时器
m_rotateTimer = new QTimer(this);
connect(m_rotateTimer, SIGNAL(timeout()), this, SLOT(ChangeUniform()));
m_rotateTimer->start(150);
}
openGL::~openGL()
{
delete vertexBuffer;
delete indexBuffer;
}
void openGL::initializeGL()
{
setGeometry(200,200, 800, 600);
glEnable(GL_DEPTH_TEST);
glEnable(GL_SMOOTH);
initializeGLFunctions();
InitShader(); //初始化着色器程序
InitBuffer(); //初始化顶点坐标
}
void openGL::resizeGL(int w, int h)
{
//设置视口的大小
glViewport(0, 0, w, h);
}
void openGL::paintGL()
{
// glViewport(0, 0, SRC_WIDTH, SRC_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shader.bind();
shader.enableAttributeArray("aPos");
shader.enableAttributeArray("aTexCoord");
glEnable(GL_TEXTURE_2D);
//绑定纹理
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureID2);
QMatrix4x4 viewMatrix; //观察矩阵
QMatrix4x4 projectionMatrix; //裁剪矩阵
viewMatrix.lookAt(cameraPos, cameraPos + cameraFront, cameraUp); //设置相机属性
projectionMatrix.perspective(60.0f, (float)SRC_WIDTH / (float)SRC_HEIGHT, 0.1f, 500.0f);//设置裁剪属性
shader.setUniformValue("view", viewMatrix);
shader.setUniformValue("projection", projectionMatrix);
//6个立方体旋转变化
for(int i=0; i<6; ++i)
{
QMatrix4x4 modelMatrix;
modelMatrix.translate(cubePosition[i]); //平移立方体
modelMatrix.scale(1.5); //立方体体积变化
float Angle = stepSize * (i+1);
modelMatrix.rotate(Angle, QVector3D(1.0f, 0.3f, 0.5f));
//旋转角度
shader.setUniformValue("model", modelMatrix);
shader.setUniformValue("mixValue", mixValue); //设置两个纹理的混合比例
glDrawArrays(GL_TRIANGLES,0,36); //绘制12个三角形,三角形有36个顶点
}
shader.disableAttributeArray("aPos");
shader.disableAttributeArray("aTexCoord");
glDisable(GL_TEXTURE_2D);
shader.release();
}
void openGL::InitShader()
{
shader.addShaderFromSourceCode(QGLShader::Vertex, vertexShaderSource);
shader.addShaderFromSourceCode(QGLShader::Fragment, fragmentShaderSource);
shader.link();
}
void openGL::InitBuffer()
{
//初始化着色器程序
vertexBuffer = new QGLBuffer(QGLBuffer::VertexBuffer);
indexBuffer = new QGLBuffer(QGLBuffer::IndexBuffer);
shader.bind();
vertexBuffer->create();
vertexBuffer->bind();
vertexBuffer->allocate(vertices, sizeof(vertices));
vertexBuffer->setUsagePattern(QGLBuffer::StaticDraw);
shader.setAttributeBuffer("aPos", GL_FLOAT, 0, 3, 20);
shader.setAttributeBuffer("aTexCoord", GL_FLOAT, 12, 2, 20);
//加载第一个纹理
QImage texImage, tempImage;
bool isLoadOK = tempImage.load("./texture/container.jpg");
texImage = QGLWidget::convertToGLFormat(tempImage);
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
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);
glTexImage2D(GL_TEXTURE_2D, 0, 3, texImage.width(), texImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage.bits());
glGenerateMipmap(GL_TEXTURE_2D);
//加载第二个纹理
bool isLoadOK2 = tempImage.load("./texture/bricks2.jpg");
texImage = QGLWidget::convertToGLFormat(tempImage);
glGenTextures(1, &textureID2);
glBindTexture(GL_TEXTURE_2D, textureID2);
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);
glTexImage2D(GL_TEXTURE_2D, 0, 3, texImage.width(), texImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage.bits());
glGenerateMipmap(GL_TEXTURE_2D);
glUniform1i(glGetUniformLocation(shader.programId(), "texture1"), 0);
glUniform1i(glGetUniformLocation(shader.programId(), "texture2"), 1);
vertexBuffer->release();
shader.release();
}
void openGL::keyPressEvent(QKeyEvent *e)
{
//方向键控制相机的位置
float cameraSpeed = 0.05f;
//前后变换
if(e->key() == Qt::Key_W)
{
cameraPos += cameraSpeed*cameraFront;
}
if(e->key() == Qt::Key_S)
{
cameraPos -= cameraSpeed*cameraFront;
}
//左右变换
if(e->key() == Qt::Key_A)
{
QVector3D temp;
cameraPos -= (temp.crossProduct(cameraFront, cameraUp))*cameraSpeed;
}
if(e->key() == Qt::Key_D)
{
QVector3D temp;
cameraPos += (temp.crossProduct(cameraFront, cameraUp))*cameraSpeed;
}
}
void openGL::ChangeUniform()
{
//纹理变化
if(mixValue > 1.0f)
{
mixValue = 1.0f;
directFlag = !directFlag;
}
if(mixValue < 0.0f)
{
mixValue = 0.0f;
directFlag = !directFlag;
}
if(directFlag)
{
mixValue += 0.05f;
}
else
{
mixValue -= 0.05;
}
//旋转角度变化
stepSize += 0.25;
updateGL();
}
运行效果如下图所示: