欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-03 23:19:31
...

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);

    }
}

相关标签: 小菜鸡爱学习