QT中学习Opengl---(坐标系统)

前言:

本文的代码是 LearnOpenGL 中对应代码,这里提供学习,大家喜欢的可去官方网站去看看:
LearnOpenGL-CNicon-default.png?t=M276https://learnopengl-cn.readthedocs.io/zh/latest/

本章记录了,opengl中坐标系统代码,然后为了方便在qt中编写。

坐标系统:

比较重要的总共有5个不同的坐标系统:

  • 局部空间(Local Space, 或者称为物体空间(Object Space))
  • 世界空间(World Space)
  • 观察空间(View Space, 或者称为视觉空间(Eye Space))
  • 裁剪空间(Clip Space)
  • 屏幕空间(Screen Space)

     为了将坐标从一个坐标系转换到另一个坐标系, 我们需要用到几个转换矩阵, 最重要的几个
分别是模型(Model)、 视图(View)、 投影(Projection)三个矩阵。 首先, 顶点坐标开始于局部
空间(Local Space), 称为局部坐标(Local Coordinate), 然后经过世界坐标(WorldCoordinate), 观察坐标(View Coordinate), 裁剪坐标(Clip Coordinate), 并最后以屏幕坐标(Screen Coordinate)结束。

1. 局部坐标是对象相对于局部原点的坐标; 也是对象开始的坐标。
2. 将局部坐标转换为世界坐标, 世界坐标是作为一个更大空间范围的坐标系统。 这些坐标
是相对于世界的原点的。
3. 接下来我们将世界坐标转换为观察坐标, 观察坐标是指以摄像机或观察者的角度观察的
坐标。
4. 在将坐标处理到观察空间之后, 我们需要将其投影到裁剪坐标。 裁剪坐标是处理-1.0到
1.0范围内并判断哪些顶点将会出现在屏幕上。
5. 最后, 我们需要将裁剪坐标转换为屏幕坐标, 我们将这一过程成为视口变换(Viewport
Transform)。 视口变换将位于-1.0到1.0范围的坐标转换到由 glViewport 函数所定义的坐
标范围内。 最后转换的坐标将会送到光栅器, 由光栅器将其转化为片段。

 其实我们记住:

 对应矩阵这样处理就可以。

因为绘制的立方体,需要用到深度测试,这样看上去才对。

 glEnable(GL_DEPTH_TEST);
 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

绘制效果:

 代码:

顶点着色器

#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 = vec2(aTexCoord.x, aTexCoord.y);
}

 片段着色器

#version 330 core
out vec4 FragColor;

in vec2 TexCoord;

// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;

void main()
{
        // linearly interpolate between both textures (80% container, 20% awesomeface)
        FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
        //FragColor =texture(texture2,TexCoord);
}

头文件:

#ifndef BKQOPENGLW_H
#define BKQOPENGLW_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QTimer>
class BKQOpenglW : public QOpenGLWidget, QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    enum Shape{None,Rect,circle,Triangle};
    explicit BKQOpenglW(QWidget *parent = nullptr);
    ~BKQOpenglW();
    void drawShapes(Shape shape);
    void setWireFrame(bool b);
protected:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();

signals:

public slots:

private:
    unsigned int VBO, VAO,EBO;
    Shape m_Shape;
    QOpenGLShaderProgram shaderProgram;
    unsigned int texture;
    QOpenGLTexture *pTexture;
    QOpenGLTexture *pTexture2;

    QTimer timer;
    int rotate{ 0 };
};

#endif // BKQOPENGLW_H

对应cpp文件:

#include "bkqopenglw.h"
#include<iostream>
#include <QDebug>
#include <QSurfaceFormat>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#if 0
float vertices[] = {
        // positions          // colors           // texture coords
         0.8f,  0.8f, 0.0f,   1.0f, 0.0f, 0.0f,   2.0f, 2.0f, // top right
         0.8f, -0.8f, 0.0f,   0.0f, 1.0f, 0.0f,   2.0f, 0.0f, // bottom right
        -0.8f, -0.8f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.8f,  0.8f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 2.0f  // top left
    };

#endif

//顶点数据(盒子六个面,一个面两个三角)
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
};


unsigned int indices[] = {  // note that we start from 0!
    0, 1, 3,  // first Triangle
    1, 2, 3   // second Triangle
};


//绘制多个盒子
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)
};


BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
//    QSurfaceFormat fmt = format();
//    fmt.setRenderableType(QSurfaceFormat::OpenGL);
//    fmt.setProfile(QSurfaceFormat::CoreProfile);
    fmt.setVersion(3, 3);
//    //当启用多重采样时,将每个像素的首选样本数设置为numSamples
//    fmt.setSamples(4);
//    setFormat(fmt);


    connect(&timer,&QTimer::timeout,this,[this](){
            rotate+=2;
            if(isVisible()){
                update();
            }
        });
        timer.setInterval(50);

}

BKQOpenglW::~BKQOpenglW()
{
    makeCurrent();
    glDeleteVertexArrays(1,&VAO);
    glDeleteBuffers(1,&VBO);
    doneCurrent();
}

void BKQOpenglW::drawShapes(BKQOpenglW::Shape shape)
{
    m_Shape = shape;
    update();
}

void BKQOpenglW::setWireFrame(bool b)
{
    makeCurrent();
    if(b)
    {
       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    }
    else {
       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }
    update();
    doneCurrent();
}

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

    //    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,vertexShaderSource);
    //    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,fragmentShaderSource);
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/shader.vs");
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/shader.fs");
    shaderProgram.link();
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //绑定ebo
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    // texture coord attribute
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    //绑定纹理
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    pTexture = new QOpenGLTexture(QImage(":/images/images/brickwall.jpg").mirrored());
    pTexture2 = new QOpenGLTexture(QImage(":/images/images/awesomeface.png").mirrored());
    shaderProgram.bind();
    shaderProgram.setUniformValue("texture1",0);
    shaderProgram.setUniformValue("texture2",1);
    //默认为GL_REPEAT 重复 GL_MIRRORED_REPEAT镜像  GL_CLAMP_TO_EDGE 边缘拉伸 GL_CLAMP_TO_BORDER 超出部分使用用户定义
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT);	// we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT);

    QMatrix4x4 view; //观察矩阵,后退一点
    view.translate(QVector3D(0.0f, 0.0f, -3.0f));
    shaderProgram.setUniformValue("view", view);
    QMatrix4x4 projection; //透视投影
    //坐标到达观察空间之后,我们需要将其投影到裁剪坐标。
    //裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上
    //参数1:指定视景体的视野的角度
    //参数2:指定你的视景体的宽高比
    //参数3:指定观察者到视景体的最近的裁剪面的距离(正数)
    //参数4:指定观察者到视景体最远的裁剪面距离(正数)
    projection.perspective(45.0f, 1.0f * width() / height(), 0.1f, 100.0f);
    shaderProgram.setUniformValue("projection", projection);
    shaderProgram.release();

    timer.start();





    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0);

}

void BKQOpenglW::resizeGL(int w, int h)
{
       glViewport(0,0,w,h);
}

void BKQOpenglW::paintGL()
{

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.2f, 0.3f, 0.3f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    shaderProgram.bind();
    glBindVertexArray(VAO);
    switch (m_Shape) {
    case Triangle:
        glDrawArrays(GL_TRIANGLES,0,3);
        break;
    case Rect:
        pTexture->bind(0);
        pTexture2->bind(1);

        for (unsigned int i = 0; i < 10; i++) {
               //计算模型矩阵
               QMatrix4x4 model;
               //平移
               model.translate(cubePositions[i]);
               //这样每个箱子旋转的速度就不一样
               float angle = (i + 1.0f) * rotate;
               //旋转
               model.rotate(angle, QVector3D(1.0f, 0.3f, 0.5f));
               //传入着色器并绘制
               shaderProgram.setUniformValue("model", model);
               glDrawArrays(GL_TRIANGLES, 0, 36);
           }
        break;
    default:
        break;
    }

}

最后的话:

 每天写代码时间不多,上班时间还是比较长,写博客不易,喜欢的朋友,可以关注偶。

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值