先看效果:
顶点着色器:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTextureCoord;
out vec3 outColor;
out vec2 textureCoord;
//矩阵必须初始化,初始化单位矩阵,否则GLSL语言中默认矩阵是0矩阵
uniform mat4 trans = mat4(1.0);
uniform mat4 model = mat4(1.0);
uniform mat4 view = mat4(1.0);
uniform mat4 projection = mat4(1.0);
void main(){
//gl_Position = trans * vec4(aPos.x, aPos.y, aPos.z, 1.0);//在矩阵乘法中是右乘左,与显实的乘法不同
gl_Position = projection * view * model * vec4(aPos, 1.0);
textureCoord = aTextureCoord;
}
片段着色器:
#version 330 core
out vec4 fragColor;
in vec3 outColor;//从顶点着色器中传过来的颜色
in vec2 textureCoord;
uniform sampler2D textureImg;
uniform sampler2D textureCpp;
void main(){
//fragColor = texture(textureImg, textureCoord);
fragColor = mix(texture(textureImg,textureCoord), texture(textureCpp,textureCoord), 0.5);
}
相机类:
#pragma once
#include <QVector3D>
#include <qmatrix4x4.h>
// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT,
UP,
DOWN
};
// Default camera values
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.005f;
const float ZOOM = 45.0f;
class Camera {
public:
// camera Attributes
QVector3D Position;
QVector3D Front;
QVector3D Up;
QVector3D Right;
QVector3D WorldUp;
// euler Angles
float Yaw;
float Pitch;
// camera options
float MovementSpeed;
float MouseSensitivity;
float Zoom;
// constructor with vectors
Camera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(QVector3D(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM) {
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
// constructor with scalar values
Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(QVector3D(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM) {
Position = QVector3D(posX, posY, posZ);
WorldUp = QVector3D(upX, upY, upZ);
Yaw = yaw;
Pitch = pitch;
updateCameraVectors();
}
~Camera();
// returns the view matrix calculated using Euler Angles and the LookAt Matrix
QMatrix4x4 GetViewMatrix() {
QMatrix4x4 view;
view.lookAt(Position, Position + Front, Up);
return view;
}
// processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void ProcessKeyboard(Camera_Movement direction, float deltaTime) {
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
if (direction == UP)
Position += WorldUp * velocity;
if (direction == DOWN)
Position -= WorldUp * velocity;
//updateCameraVectors();
}
// processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch = true) {
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
// make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch) {
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
// update Front, Right and Up Vectors using the updated Euler angles
updateCameraVectors();
}
// processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void ProcessMouseScroll(float yoffset) {
Zoom -= (float)yoffset;
if (Zoom < 1.0f)
Zoom = 1.0f;
if (Zoom > 45.0f)
Zoom = 45.0f;
}
private:
// calculates the front vector from the Camera's (updated) Euler Angles
void updateCameraVectors() {
// calculate the new Front vector
QVector3D front;
front.setX(cos(Yaw) * cos(Pitch));
front.setY(sin(Pitch));
front.setZ(sin(Yaw) * cos(Pitch));
Front = front.normalized();
// also re-calculate the Right and Up vector
Right = QVector3D::crossProduct(Front, WorldUp).normalized();
Up = QVector3D::crossProduct(Right, Front).normalized();
}
};
界面类:
#pragma once
#include <QOpenGLWindow>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QDebug>
#include <QOpenGLTexture>
#include <QElapsedTimer>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include "camera.h"
class CameraWnd : public QOpenGLWindow {
Q_OBJECT
public:
CameraWnd();
~CameraWnd();
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
void keyPressEvent(QKeyEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private:
class QOpenGLTexture *_texture1;
class QOpenGLTexture *_texture2;
QElapsedTimer m_time;
Camera m_camera;
float m_lastX;
float m_lastY;
float m_deltaTime = 0.0f;
float m_lastFrame = 0.0f;
bool m_firstMouse = true;
bool m_isMousePress = false;
class QOpenGLFunctions_3_3_Core* _openGLCore;
QOpenGLShaderProgram _shaderProgram;//着色器程序,所里系统所有的着色器
};
#include "CameraWnd.h"
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QOpenGLFunctions_3_3_Core>
static GLuint VBO, VAO = 0;
// world space positions of our cubes
static QVector3D cubePositions[] = {
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.7f, 3.0f, -7.5f),
QVector3D(1.3f, -2.0f, -2.5f),
QVector3D(1.5f, 2.0f, -2.5f),
QVector3D(1.5f, 0.2f, -1.5f),
QVector3D(-1.3f, 1.0f, -1.5f)
};
CameraWnd::CameraWnd() {
m_camera.Position = QVector3D(0.0f, 0.0f, 3.0f);
m_lastX = width() / 2;
m_lastY = height() / 2;
}
CameraWnd::~CameraWnd() {
}
void CameraWnd::initializeGL() {
_openGLCore = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
_openGLCore->glEnable(GL_DEPTH_TEST);
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
};
_openGLCore->glGenVertexArrays(1, &VAO);
_openGLCore->glGenBuffers(1, &VBO);
_openGLCore->glBindVertexArray(VAO);
_openGLCore->glBindBuffer(GL_ARRAY_BUFFER, VBO);
_openGLCore->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// position attribute
_openGLCore->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
_openGLCore->glEnableVertexAttribArray(0);
// texture coord attribute
_openGLCore->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
_openGLCore->glEnableVertexAttribArray(1);
//垂直镜像mirrored
_texture1 = new QOpenGLTexture(QImage("E:/Projects/QtGuiTest/OPenGLApp/shader/1.jpg").mirrored());
if (!_texture1->isCreated()) {
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
_texture1->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
_texture1->setMagnificationFilter(QOpenGLTexture::Linear);
_texture2 = new QOpenGLTexture(QImage("E:/Projects/QtGuiTest/OPenGLApp/shader/2.png").mirrored());
if (!_texture2->isCreated()) {
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
_texture2->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
_texture2->setMagnificationFilter(QOpenGLTexture::Linear);
//设置纹理单元编号
_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "E:/Projects/QtGuiTest/OPenGLApp/shader/Camera.vert");
_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "E:/Projects/QtGuiTest/OPenGLApp/shader/Camera.frag");
_shaderProgram.link();
//如果是一张图片就不用绑定,默认绑定。如果是多于1张就需要主动绑定,
_shaderProgram.bind();
/*
** textureImg:对应的片元着色器的 uniform sampler2D textureImg;
** textureCpp:对应的片元着色器的 uniform sampler2D textureCpp;
*/
_shaderProgram.setUniformValue("textureImg", 0);
_shaderProgram.setUniformValue("textureCpp", 1);
m_time.start();
}
void CameraWnd::resizeGL(int w, int h) {
_openGLCore->glViewport(0, 0, w, h);
}
void CameraWnd::paintGL() {
_openGLCore->glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
_openGLCore->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float currentFrame = (float)m_time.elapsed() / 100;
m_deltaTime = currentFrame - m_lastFrame;
m_lastFrame = currentFrame;
//激活纹理单元0
_openGLCore->glActiveTexture(GL_TEXTURE0);
_texture1->bind();
_openGLCore->glActiveTexture(GL_TEXTURE1);
_texture2->bind();
// render container
_shaderProgram.bind();
QMatrix4x4 view = m_camera.GetViewMatrix();
QMatrix4x4 projection;
view.translate(QVector3D(0.0f, 0.0f, -3.0f));
projection.perspective(m_camera.Zoom, (float)width() / (float)height(), 0.1f, 100.0f);
for (unsigned int i = 0; i < 10; i++) {
QMatrix4x4 model;
model.translate(cubePositions[i]);
float angle;
if (i % 3 == 0) {
angle = (float)m_time.elapsed() / 10;
} else {
angle = i * 20.0f;
}
model.rotate(angle, QVector3D(1.0f, 0.3f, 0.5f));
_shaderProgram.setUniformValue("model", model);
_shaderProgram.setUniformValue("view", view);
_shaderProgram.setUniformValue("projection", projection);
_openGLCore->glDrawArrays(GL_TRIANGLES, 0, 36);
}
update();
}
void CameraWnd::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_A) {
m_camera.ProcessKeyboard(Camera_Movement::LEFT, m_deltaTime);
} else if (event->key() == Qt::Key_D) {
m_camera.ProcessKeyboard(Camera_Movement::RIGHT, m_deltaTime);
} else if (event->key() == Qt::Key_W) {
m_camera.ProcessKeyboard(Camera_Movement::FORWARD, m_deltaTime);
} else if (event->key() == Qt::Key_S) {
m_camera.ProcessKeyboard(Camera_Movement::BACKWARD, m_deltaTime);
} else if (event->key() == Qt::Key_E) {
m_camera.ProcessKeyboard(Camera_Movement::UP, m_deltaTime);
} else if (event->key() == Qt::Key_Q) {
m_camera.ProcessKeyboard(Camera_Movement::DOWN, m_deltaTime);
}
}
void CameraWnd::mouseMoveEvent(QMouseEvent *event) {
float xpos = static_cast<float>(event->pos().x());
float ypos = static_cast<float>(event->pos().y());
if (!m_isMousePress)
return;
if (m_firstMouse) {
m_lastX = xpos;
m_lastY = ypos;
m_firstMouse = false;
}
float xoffset = xpos - m_lastX;
float yoffset = m_lastY - ypos; // reversed since y-coordinates go from bottom to top
m_lastX = xpos;
m_lastY = ypos;
m_camera.ProcessMouseMovement(xoffset, yoffset);
}
void CameraWnd::wheelEvent(QWheelEvent *event) {
m_camera.ProcessMouseScroll((float)event->angleDelta().y() / 60.0f);
}
void CameraWnd::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton)
m_isMousePress = true;
}
void CameraWnd::mouseReleaseEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton) {
m_isMousePress = false;
m_firstMouse = true;
}
}
aaa