您当前的位置: 首页 >  qt

龚建波

暂无认证

  • 3浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

OpenGL with QtWidgets:练习之扑克翻转

龚建波 发布时间:2020-02-04 10:15:38 ,浏览量:3

(本文是LearnOpenGL的学习笔记,教程中文翻译地址https://learnopengl-cn.github.io/(备用地址https://learnopengl-cn.readthedocs.io/zh/latest/),写于 2020-2-4 ,并在 2021-9-5 进行了更新)

1.实现思路

(本来想拿扑克的正反面来做练习,奈何没找到免费的资源图片,白嫖不易,于是拿两张明星图片来代替了)

代码主要参考教程 "坐标系统" 一节的源码,把顶点坐标和纹理坐标传递给着色器,然后旋转model矩阵就能实现了翻转效果了。

两个纹理的位置是一样的,那么如何区分正反面呢?在OpenGL中默认逆时针的顶点顺序是正面,所以我们把两个面的顶点顺序反一下,一个顺时针一个逆时针就可以了。有了正反面,还需要把背面隐藏起来,OpenGL中有面剔除的功能,我们把背面剔除即可。(参考:https://www.jianshu.com/p/4e165df3ae26)

glEnable(GL_CULL_FACE); //开启面剔除
glCullFace(GL_BACK); //剔除背面
//glFrontFace(GL_CW); //逆时针顶点为正面GL_CCW(默认),顺时针GL_CW

解决了正反面问题,还有个问题是如何把两张图分别贴到正反面 。开始我想的是用两个着色器程序分别绘制,但是感觉太麻烦了,索性把两张图合并到一起(这样就只有一个纹理贴图了),用纹理坐标来分割两张图贴到正反面。(如果其中一个图左右翻转了,把纹理坐标x翻转下就可以了)

    //VAO,VBO(一个面两个三角)360/460(应该用qimage获取宽高,这里设定死了)
    const float texture_width=360.0f/460.0f;
    float vertices[] = {
        -texture_width/2, -0.5f, 0.0f,  0.0f, 0.5f, //左下角
        texture_width/2, -0.5f, 0.0f,  1.0f, 0.5f, //右下角
        texture_width/2,  0.5f, 0.0f,  1.0f, 1.0f, //右上角

        texture_width/2,  0.5f, 0.0f,  1.0f, 1.0f, //右上角
        -texture_width/2,  0.5f, 0.0f,  0.0f, 1.0f, //左上角
        -texture_width/2, -0.5f, 0.0f,  0.0f, 0.5f, //左下角

        -texture_width/2, -0.5f, 0.0f,  1.0f, 0.0f, //左下角
        -texture_width/2,  0.5f, 0.0f,  1.0f, 0.5f, //左上角
        texture_width/2,  0.5f, 0.0f,  0.0f, 0.5f, //右上角

        texture_width/2,  0.5f, 0.0f,  0.0f, 0.5f, //右上角
        texture_width/2, -0.5f, 0.0f,  0.0f, 0.0f, //右下角
        -texture_width/2, -0.5f, 0.0f,  1.0f, 0.0f, //左下角
    };

坐标变换的代码用的教程里的方式,只旋转了model矩阵。

    QMatrix4x4 view; //观察矩阵,后退一点
    view.translate(QVector3D(0.0f, 0.0f, -1.5f));
    _shaderProgram.setUniformValue("view", view);
    QMatrix4x4 projection; //透视投影
    projection.perspective(45.0f, 1.0f * width() / height(), 0.1f, 100.0f);
    _shaderProgram.setUniformValue("projection", projection);
    QMatrix4x4 model;//模型矩阵
    model.rotate(_rotate, QVector3D(0.0f, 1.0f, 0.0f));
    _shaderProgram.setUniformValue("model", model);

(代码里没有堆叠的问题,所以可以不用深度缓冲,我复制粘贴没去掉)

2.实现代码

(项目git链接:https://github.com/gongjianbo/OpenGLwithQtWidgets.git)

Poker 类实现效果(左边图片右边GIF):

MyPoker类代码:

#pragma once
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//扑克反转练习
//QOpenGLWidget窗口上下文
//QOpenGLFunctions访问OpenGL接口,可以不继承作为成员变量使用
class MyPoker
        : public QOpenGLWidget
        , protected QOpenGLFunctions_3_3_Core
{
public:
    explicit MyPoker(QWidget *parent = nullptr);
    ~MyPoker();

protected:
    //【】继承QOpenGLWidget后重写这三个虚函数
    //设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
    void initializeGL() override;
    //渲染OpenGL场景,每当需要更新小部件时使用
    void paintGL() override;
    //设置OpenGL视口、投影等,每当尺寸大小改变时调用
    void resizeGL(int width, int height) override;

private:
    //着色器程序
    QOpenGLShaderProgram shaderProgram;
    //顶点数组对象
    QOpenGLVertexArrayObject vao;
    //顶点缓冲
    QOpenGLBuffer vbo;

    //纹理
    QOpenGLTexture *texture{ nullptr };
    //定时器,做动画效果
    QTimer timer{ nullptr };
    //旋转角度
    int rotate{ 0 };
};
#include "MyPoker.h"
#include 
#include 
#include 

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

MyPoker::~MyPoker()
{
    //initializeGL在显示时才调用,释放未初始化的会异常
    if(!isValid())
        return;
    //QOpenGLWidget
    //三个虚函数不需要makeCurrent,对应的操作已由框架完成
    //但是释放时需要设置当前上下文
    makeCurrent();
    vbo.destroy();
    vao.destroy();
    delete texture;
    doneCurrent();
}

void MyPoker::initializeGL()
{
    //为当前上下文初始化OpenGL函数解析
    initializeOpenGLFunctions();

    //着色器代码
    //in输入,out输出,uniform从cpu向gpu发送
    //因为OpenGL纹理颠倒过来的,所以取反vec2(aTexCoord.x, 1-aTexCoord.y);
    const char *vertex_str=R"(#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.0f);
TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
})";
    const char *fragment_str=R"(#version 330 core
in vec2 TexCoord;
uniform sampler2D texture1;
out vec4 FragColor;
void main()
{
FragColor = texture(texture1, TexCoord);
})";

    //将source编译为指定类型的着色器,并添加到此着色器程序
    if(!shaderProgram.addCacheableShaderFromSourceCode(
                QOpenGLShader::Vertex,vertex_str)){
        qDebug()            
关注
打赏
1655829268
查看更多评论
0.3829s