摄像机这篇,我感觉教程已经写得很清楚,直接上代码,翻译就完了。
camare类
#ifndef CAMERA_H
#define CAMERA_H
#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;
// An abstract camera class that processes input and calculates the corresponding Euler Angles, Vectors and Matrices for use in OpenGL
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();
}
// 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();
}
};
#endif
.h
#ifndef CAMERAWIDGET_H
#define CAMERAWIDGET_H
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QDebug>
#include <QOpenGLTexture>
#include <QElapsedTimer>
#include "Shader.h"
#include "camera.h"
namespace Ui {
class CameraWidget;
}
class HelloCamera;
class CameraWidget : public QWidget
{
Q_OBJECT
public:
explicit CameraWidget(QWidget *parent = nullptr);
~CameraWidget();
private:
Ui::CameraWidget *ui;
HelloCamera *m_contentWidget;
};
class HelloCamera : public QOpenGLWidget,protected QOpenGLExtraFunctions
{
public:
HelloCamera();
~HelloCamera();
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:
Shader *m_shader;
QOpenGLTexture *m_combine_texture1;
QOpenGLTexture *m_combine_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;
};
#endif // CAMERAWIDGET_H
cpp
#include "camerawidget.h"
#include "ui_camerawidget.h"
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWheelEvent>
CameraWidget::CameraWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::CameraWidget)
{
ui->setupUi(this);
m_contentWidget = new HelloCamera();
ui->verticalLayout->addWidget(m_contentWidget);
}
CameraWidget::~CameraWidget()
{
delete ui;
}
HelloCamera::HelloCamera()
{
m_camera.Position = QVector3D(0.0f,0.0f,3.0f);
m_lastX = width()/2;
m_lastY = height()/2;
setFocusPolicy(Qt::StrongFocus);
}
HelloCamera::~HelloCamera()
{
}
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)
};
void HelloCamera::initializeGL()
{
this->initializeOpenGLFunctions();
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
};
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 coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
m_shader = new Shader(":/shader/res/shaders/getting_started/7.4.camera.vs"
,":/shader/res/shaders/getting_started/7.4.camera.fs");
//垂直镜像mirrored
m_combine_texture1 = new QOpenGLTexture(QImage(":/texture/res/textures/container.jpg").mirrored());
if(!m_combine_texture1->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_combine_texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_combine_texture1->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_combine_texture1->setMagnificationFilter(QOpenGLTexture::Linear);
m_combine_texture2 = new QOpenGLTexture(QImage(":/texture/res/textures/awesomeface.png").mirrored());
if(!m_combine_texture2->isCreated()){
qDebug() << "Failed to load texture";
}
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_combine_texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_combine_texture2->setMinificationFilter(QOpenGLTexture::Linear);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_combine_texture2->setMagnificationFilter(QOpenGLTexture::Linear);
//设置纹理单元编号
m_shader->use();
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture1"), 0);
m_shader->m_shaderProgram.setUniformValue(m_shader->m_shaderProgram.uniformLocation("texture2"), 1);
m_time.start();
}
void HelloCamera::resizeGL(int w, int h)
{
this->glViewport(0,0,w,h);
}
void HelloCamera::paintGL()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
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
glActiveTexture(GL_TEXTURE0);
m_combine_texture1->bind();
glActiveTexture(GL_TEXTURE1);
m_combine_texture2->bind();
// render container
m_shader->use();
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));
m_shader->m_shaderProgram.setUniformValue("model",model);
m_shader->m_shaderProgram.setUniformValue("view",view);
m_shader->m_shaderProgram.setUniformValue("projection",projection);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
update();
}
void HelloCamera::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 HelloCamera::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 HelloCamera::wheelEvent(QWheelEvent *event)
{
m_camera.ProcessMouseScroll((float)event->angleDelta().y()/60.0f);
}
void HelloCamera::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
m_isMousePress = true;
}
void HelloCamera::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
m_isMousePress = false;
m_firstMouse = true;
}
}