在本教程中,我们将使用OpenGL和Qt框架创建一个简单的应用程序,该应用程序绘制多个带有纹理的立方体。我们将使用单独的顶点着色器和片段着色器文件,以便更好地组织我们的代码。
1. 引言
OpenGL是一个强大的图形渲染库,广泛用于创建3D应用程序。Qt是一个跨平台的C++应用程序开发框架,提供了OpenGL的封装,方便我们在Qt应用程序中集成OpenGL。
2. 准备工作
首先,确保你已经安装了Qt,并创建了一个Qt Widgets应用程序项目。我们将在这个项目中添加OpenGL渲染窗口。
3. 编写顶点和片段着色器
创建两个文件,一个用于顶点着色器(vertexshader.vert),一个用于片段着色器(fragmentshader.frag)。
vertexshader.vert
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoord = aTexCoord;
}
fragment_shader.frag
:
#version 330 core
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
接下来,创建一个Qt的QOpenGLWidget
类,用于在OpenGL中绘制立方体。在这个类中,我们加载纹理、读取顶点和纹理坐标数据,以及使用着色器程序绘制多个带透视的立方体。
myopenglwidget.h
:
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
MyOpenGLWidget(QWidget *parent = nullptr);
~MyOpenGLWidget() override {}
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
private:
GLuint VAO, VBO;
QOpenGLShaderProgram shaderProgram;
QMatrix4x4 model, view, projection;
QOpenGLTexture *texture;
};
#endif // MYOPENGLWIDGET_H
myopenglwidget.cpp
:
#include "myopenglwidget.h"
#include <QImage>
MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
{
}
void MyOpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
// Set up vertex data and buffers
GLfloat vertices[] = {
// Positions // Texture Coords
-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,
// Add more vertices for additional cubes...
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// Texture attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// Load and create a texture
texture = new QOpenGLTexture(QImage(":/path/to/your/texture/image.jpg").mirrored());
// Load shaders from file
shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vertex_shader.vert");
shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fragment_shader.frag");
// Link shader program
shaderProgram.link();
// Set up perspective projection matrix
resizeGL(width(), height());
}
void MyOpenGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
projection.setToIdentity();
projection.perspective(45.0f, static_cast<float>(w) / static_cast<float>(h), 0.1f, 100.0f);
}
void MyOpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shaderProgram.bind();
shaderProgram.setUniformValue("model", model);
shaderProgram.setUniformValue("view", view);
shaderProgram.setUniformValue("projection", projection);
// Bind texture
glActiveTexture(GL_TEXTURE0);
texture->bind();
shaderProgram.setUniformValue("texture1", 0);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36); // Assuming 36 vertices for a single cube
// Draw more cubes...
}