QT实现OPENGL三维画图(视角可调整)

QT实现OPENGL画图

继承QOpenGLWidget和QOpenGLFunctions实现自定义窗口类。重写QOpenGLWidget的虚函数
void paintGL() override;
void initializeGL() override;
void mouseMoveEvent(QMouseEvent*)override;
void mousePressEvent(QMouseEvent*)override;
void wheelEvent(QWheelEvent*)override;
实现camera类,用于响应输入,改变观察矩阵,投影矩阵,从而实现视角控制。
camera.h

#ifndef __CAMERA_H__
#define __CAMERA_H__

#include <QOpenGLFunctions>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.03f;
const float ZOOM = 45.0f;
//摄像机移动方向
enum Camera_Movement { 
	FORWARD,
	BACKWARD,
	LEFT,
    RIGHT,
    UP,
    DOWN
};

class Camera
{ 
public:
    glm::vec3 Position;
    glm::vec3 Forward;
    glm::vec3 Up;
    glm::vec3 Right;
    glm::vec3 World_up;

    float Yaw;
    float Pitch;

    float MovementSpeed;
    float Mouse_Sensiticity;
    float Zoom;
    bool flip_y = false;

    Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 5.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH);
    Camera(float pos_x, float pos_y, float pos_z, float up_x, float up_y, float up_z, float yaw, float pitch);
    ~Camera();

    glm::mat4 GetViewMatrix();
    void ProcessKeyboard(Camera_Movement direction, float deltaTime);
    void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true);
    void ProcessMouseScroll(float yoffset);

private:
    void UpdateCameraVectors();
};

#endif

camera.cpp

#include "Camera.h"

Camera::Camera(glm::vec3 position, glm::vec3 up, float yaw, float pitch)
: Forward(glm::vec3(0.0f, 0.0f, -1.0f))
, MovementSpeed(SPEED)
, Mouse_Sensiticity(SENSITIVITY)
, Zoom(ZOOM)
{ 
    this->Position = position;
    this->World_up = up;
    this->Yaw = yaw;
    this->Pitch = pitch;
    UpdateCameraVectors();
}

Camera::Camera(float pos_x, float pos_y, float pos_z, float up_x, float up_y, float up_z, float yaw, float pitch)
: Forward(glm::vec3(0.0f, 0.0f, -1.0f))
, MovementSpeed(SPEED)
, Mouse_Sensiticity(SENSITIVITY)
, Zoom(ZOOM)
{ 
	this->Position = glm::vec3(pos_x, pos_y, pos_z);
	this->World_up = glm::vec3(up_x, up_y, up_z);
	this->Yaw = yaw;
	this->Pitch = pitch;
	UpdateCameraVectors();
}

Camera::~Camera()
{ 

}

glm::mat4 Camera::GetViewMatrix()
{   
    return glm::lookAt(Position, Position + Forward, Up);
}

//对应键盘移动事件
void Camera::ProcessKeyboard(Camera_Movement direction, float deltaTime)
{ 
	float velocity = MovementSpeed * deltaTime;
	if (direction == FORWARD)
		Position += Forward * velocity;
	if (direction == BACKWARD)
		Position -= Forward * velocity;
	if (direction == LEFT)
		Position -= Right * velocity;
	if (direction == RIGHT)
		Position += Right * velocity;
    if (direction == UP)
        Position += Up * velocity;
    if (direction == DOWN)
        Position -= Up * velocity;
}
//对应鼠标移动事件
void Camera::ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch)
{ 
	xoffset *= Mouse_Sensiticity;
	yoffset *= Mouse_Sensiticity;

	Yaw += xoffset;
	Pitch += yoffset;

	if (constrainPitch)
	{ 
		if (Pitch > 89.0f)
			Pitch = 89.0f;
		if (Pitch < -89.0f)
			Pitch = -89.0f;
	}

	UpdateCameraVectors();
}
//对应鼠标滚轮事件
void Camera::ProcessMouseScroll(float yoffset)
{ 
	if (Zoom >= 1.0f && Zoom <= 45.0f)
		Zoom -= yoffset;
	if (Zoom <= 1.0f)
		Zoom = 1.0f;
	if (Zoom >= 45.0f)
		Zoom = 45.0f;
}


void Camera::UpdateCameraVectors()
{ 
	glm::vec3 front;
	front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
	front.y = sin(glm::radians(Pitch));
	front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
	Forward = glm::normalize(front);
	Right = glm::normalize(glm::cross(Forward, World_up)); 
	Up = glm::normalize(glm::cross(Right, Forward));
}

openwidget.h

#ifndef OPENWIDGET_H
#define OPENWIDGET_H
#include<QOpenGLWidget>
#include<QOpenGLFunctions_3_3_Compatibility>
#include<QOpenGLShader>
#include<QOpenGLShaderProgram>
#include"Camera.h"
class OpenWidget  : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Compatibility
{ 
public:
    OpenWidget();
    ~OpenWidget() override;
    void keyPressEvent(QKeyEvent*)override;

private:
    GLuint VAO;
    GLuint VBO;
    GLuint _VAO;
    GLuint _VBO;
    QOpenGLShader* vshader;
    QOpenGLShader* fshader;
    QOpenGLShaderProgram* shaderProgram;
    QOpenGLShader* _vshader;
    QOpenGLShader* _fshader;
    QOpenGLShaderProgram* _shaderProgram;
    GLuint texture;
    GLuint texture1;
    GLuint texture2;
    GLuint texture3;
    GLuint texture4;
    Camera camera;
    QPoint prepoint;
protected:
    void paintGL() override;
    void initializeGL() override;
    void mouseMoveEvent(QMouseEvent*)override;
    void mousePressEvent(QMouseEvent*)override;
    void wheelEvent(QWheelEvent*)override;


};

#endif // OPENWIDGET_H

openwidget.cpp

#define STB_IMAGE_IMPLEMENTATION
#include<QTime>
#include<QMouseEvent>
#include "openwidget.h"
#include"stb/stb_image.h"
#include"glm/glm.hpp"
#include"glm/gtc/type_ptr.hpp"
#include "glm/gtc/matrix_transform.hpp"

OpenWidget::OpenWidget()
{ 


}

OpenWidget::~OpenWidget()
{ 
    //释放VAOVBO
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteVertexArrays(1, &_VAO);
    glDeleteBuffers(1, &_VBO);
}

void OpenWidget::initializeGL()
{ 
    initializeOpenGLFunctions();

    //glClearColor(0.0f, 0.0f, 0.0f, 0.1f);
    //深度测试
    glEnable(GL_DEPTH_TEST);
    //线框模式
    //glPolygonMode(GL_FRONT_AND_BACK ,GL_LINE );
    glEnable(GL_BLEND);
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);  // Antialias the lines
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //着色器
    shaderProgram=new QOpenGLShaderProgram;
    vshader=new QOpenGLShader(QOpenGLShader::Vertex,shaderProgram);
    fshader=new QOpenGLShader(QOpenGLShader::Fragment,shaderProgram);
    vshader->compileSourceCode(
                                "#version 330 core\n"
                               "layout (location = 0) in vec3 aPos;\n"
                               "layout (location = 1) in vec3 PosColor;\n"
                                "layout (location = 2) in vec2 aTexCoord;\n"
                               "out vec3 positionColor;\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.0);\n"
                                     " positionColor=PosColor;\n"
                                     "TexCoord = aTexCoord;\n"
                              " }\n"
                               );
    fshader->compileSourceCode(
                "#version 330 core\n"
                "out vec4 FragColor;\n"
                "in vec3 positionColor;\n"
                "in vec2 TexCoord;\n"
                "uniform sampler2D ourTexture;\n"
                "void main()\n"
                "{\n"
                "FragColor = texture(ourTexture, TexCoord) * vec4(positionColor, 1.0);\n"
                "}\n"
                );
    shaderProgram->addShader(vshader);
    shaderProgram->addShader(fshader);
    shaderProgram->link();
    //纹理
    glEnable(GL_TEXTURE_2D);//允许采用2D纹理技术
    glShadeModel(GL_SMOOTH);//设置阴影平滑模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//当所显示的纹理比加载进来的纹理小时,采用GL_LINEAR的方法来处理
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//当所显示的纹理比加载进来的纹理大时,采用GL_LINEAR的方法来处理
    glGenTextures(1,&texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    int width, height, nrChannels;
    unsigned char *data = stbi_load("D:/1 a project/Fractal_Tree/Fractal_Tree/IMG_20200408_142732.jpg", &width, &height, &nrChannels, 0);
        if (data)
       { 
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
            glGenerateMipmap(GL_TEXTURE_2D);
         }
        else
        { 
              qDebug("Failed to load texture" );
         }
    stbi_image_free(data);
    glUniform1i(glGetUniformLocation(shaderProgram->programId(), "texture"), 0);
     //顶点数据
    float vertices[] = { 
            // 位置 // 颜色 //纹理
            0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
            -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
            0.0f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
            0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f,0.0f, 0.0f,
            -0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f,1.0f, 0.0f,
            0.0f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,0.5f, 1.0f
        };

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    //绑定VAO
    glBindVertexArray(VAO);

    //绑定VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //把顶点数组复制到VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8* sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // 颜色属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8* sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    //纹理坐标
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8* sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    //解除绑定VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    //解除绑定VAO
    glBindVertexArray(0);
    }
    void OpenWidget::paintGL()
{ 
    QMetaObject::invokeMethod(this,"update",Qt::QueuedConnection);
    glClearColor(0.3f, 0.3f, 0.3f, 0.3f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //paint
    //激活着色器
    glUseProgram(shaderProgram->programId());
    // Transform坐标变换矩阵
    float ra=QTime(0,0,0).secsTo(QTime::currentTime());
    glm::mat4 model(1);//model矩阵,局部坐标变换至世界坐标
    model = glm::rotate(model, (float)glm::radians(30.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    glm::mat4 view(1);//view矩阵,世界坐标变换至观察坐标系
    view = camera.GetViewMatrix();
    glm::mat4 projection(1);//projection矩阵,投影矩阵
    projection = glm::perspective(glm::radians(camera.Zoom), (float)this->width()/this->height(), 0.1f, 100.0f);
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram->programId(),"model"), 1, GL_FALSE,&model[0][0]);
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram->programId(),"view"), 1, GL_FALSE,&view[0][0]);
    glUniformMatrix4fv(glGetUniformLocation(shaderProgram->programId(),"projection"), 1, GL_FALSE,&projection[0][0]);
    //绑定顶点缓存对象
    glBindVertexArray(VAO);
    glBindTexture(GL_TEXTURE_2D, texture);
    //开始绘制
    glDrawArrays(GL_TRIANGLES, 0, 6);
    //解除绑定
    glBindVertexArray(0);
    }
    void OpenWidget::mouseMoveEvent(QMouseEvent *event)
{ 
    qDebug("jjjj");
    float dx=event->pos().x()-prepoint.x();
    float dy=prepoint.y()-event->pos().y();
    prepoint=event->pos();
    camera.ProcessMouseMovement(dx,dy);
}

void OpenWidget::mousePressEvent(QMouseEvent *event)
{ 
    prepoint=event->pos();
}

void OpenWidget::wheelEvent(QWheelEvent *event)
{ 
    float dy=event->delta()/20;
    camera.ProcessMouseScroll(dy);
}

void OpenWidget::keyPressEvent(QKeyEvent *event)
{ 
    float sensity=0.1f;
    if(event->key()==Qt::Key_A)
    { 
        camera.ProcessKeyboard(LEFT,sensity);

    }
    if(event->key()==Qt::Key_D)
    { 
        camera.ProcessKeyboard(RIGHT,sensity);

    }
    if(event->key()==Qt::Key_W)
    { 
        camera.ProcessKeyboard(FORWARD,sensity);

    }
    if(event->key()==Qt::Key_S)
    { 
        camera.ProcessKeyboard(BACKWARD,sensity);

    }
    if(event->key()==Qt::Key_Q)
    { 
        camera.ProcessKeyboard(UP,sensity);

    }
    if(event->key()==Qt::Key_Z)
    { 
        camera.ProcessKeyboard(DOWN,sensity);

    }
}

    原文作者:三十而学
    原文地址: https://blog.csdn.net/qq_42734954/article/details/105840691
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞