(本文是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 <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QVector3D>
#include <QMatrix4x4>
#include <QTimer>//扑克反转练习
//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 <QPushButton>
#include <QWidget>
#include <QDebug>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()<<"compiler vertex error"<<shaderProgram.log();}if(!shaderProgram.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment,fragment_str)){qDebug()<<"compiler fragment error"<<shaderProgram.log();}//使用addShader()将添加到该程序的着色器链接在一起。if(!shaderProgram.link()){qDebug()<<"link shaderprogram error"<<shaderProgram.log();}//VAO,VBO(一个面两个三角)宽高比360/460const QImage img_temp(":/liuyifei.png");//上下两张图,所以高度除以二const float texture_width=1.0f*img_temp.width()/(img_temp.height()/2);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, //左下角};vao.create();vao.bind();//QOpenGLVertexArrayObject::Binder vaoBind(&vao);vbo=QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);vbo.create();vbo.bind();vbo.allocate(vertices,sizeof(vertices));//参数1对应layout//顶点shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(GLfloat) * 5);shaderProgram.enableAttributeArray(0);//纹理坐标shaderProgram.setAttributeBuffer(1, GL_FLOAT, sizeof(GLfloat) * 3, 2, sizeof(GLfloat) * 5);shaderProgram.enableAttributeArray(1);// texture//直接生成绑定一个2d纹理, 并生成多级纹理MipMapstexture = new QOpenGLTexture(img_temp, QOpenGLTexture::GenerateMipMaps);if(!texture->isCreated()){qDebug() << "Failed to load texture";}// set the texture wrapping parameters// 等于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);texture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);texture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);// set texture filtering parameters//等价于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);texture->setMinificationFilter(QOpenGLTexture::Linear);texture->setMagnificationFilter(QOpenGLTexture::Linear);shaderProgram.bind();shaderProgram.setUniformValue("texture1", 0);shaderProgram.release();timer.start();
}void MyPoker::paintGL()
{glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//清除深度缓冲glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//Z缓冲(Z-buffer),深度缓冲(Depth Buffer)。glEnable(GL_DEPTH_TEST);glEnable(GL_CULL_FACE); //剔除glCullFace(GL_BACK); //剔除背面//glFrontFace(GL_CW); //默认逆时针顶点为正面GL_CCWglActiveTexture(GL_TEXTURE0);texture->bind();shaderProgram.bind();vao.bind();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);glDrawArrays(GL_TRIANGLES, 0, 12);vao.release();texture->release();shaderProgram.release();
}void MyPoker::resizeGL(int width, int height)
{glViewport(0, 0, width, height);
}

OpenGL with QtWidgets:练习之扑克翻转相关推荐

  1. OpenGL with QtWidgets:练习之甜甜圈

    甜甜圈是 <OpenGL 超级宝典>上的一个示例,用来演示面剔除和深度测试应用,原本的代码顶点和着色器部分不便于学习,我就重新写了下,略去了法线和光照相关. 当我们对渲染出来的甜甜圈进行旋 ...

  2. OpenGL with QtWidgets:投光物、多光源

     (本文是LearnOpenGL的学习笔记, 教程中文翻译地址https://learnopengl-cn.github.io/(备用地址https://learnopengl-cn.readthed ...

  3. OpenGL with QtWidgets:练习之绘制2D环形进度条

    1.实现思路 这里主要涉及几个点:绘制圆环,绘制文字,动画,抗锯齿. 绘制圆环网上有些人是计算好圆边的顶点后传入的,我这里直接在片段着色器里根据距离圆心的距离来渲染的圆环. void main() { ...

  4. linux更新nvidia驱动程序,NVIDIA 440.64 for Linux显示驱动程序下载,附更新内容及安装方法...

    NVIDIA 440.64 for Linux 64-bit版显示驱动程序在2020.2.28发布了,以下为你介绍更新主要内容.产品支持.已知问题及安装方法等信息. 关于下载 用户可到 https:/ ...

  5. pd.read_excel()和 pd.to_excel() 参数详解

    pandas.read_excel(io,sheet_name = 0,header = 0,names = None,index_col = None,usecols = None,squeeze ...

  6. OpenGL纹理上下颠倒翻转的三种解决办法(转)

    综述 在使用OpenGL函数加载纹理到图形时,经常遇到纹理上下颠倒的问题.原因是因为OpenGL要求纹理坐标原点在图片最下面,如图: 而图片信息中的原点一般都在最上方,一行行记录下来的,就会导致整个图 ...

  7. OpenGL ES之纹理翻转的解决策略

    原因分析 在前面的文章:OpenGL ES之Swift使用GLSL语言渲染图片的显示和OpenGL ES之GLSL渲染图片显示的整体流程中,我们都对图片纹理做了翻转的处理,不做处理,最后看到的图片显示 ...

  8. android opengl旋转,OpenGL纹理旋转及翻转问题详解

    大家好,我是程序员kenney,今天给大家讲解一下Android上OpenGL开发可能会遇到的一些纹理旋转及翻转的问题,其中有些原理在其它平台上如ios,osx上也是类似的.纹理旋转的问题一定要搞清楚 ...

  9. 【逗老师的小技巧】树莓派4翻转屏幕,加载OpenGL驱动

    树莓派4之前的版本上,屏幕旋转用的是修改config.txt文件,而在树莓派4上,因为改了驱动程序,再修改config.txt文件就不起作用了. 网上看到的办法,基本都说了 但是这里面有个坑,有些HD ...

最新文章

  1. Spring 泛型依赖注入
  2. PMP-【第12章 项目采购管理】-2021-2-17(252页-274页)
  3. MybatisPlus学习(四)条件构造器Wrapper方法详解
  4. python学习day-4 集合与函数
  5. android web developer,Growth: 一个关于如何成为优秀Web Developer 的 App
  6. java分页插件_IT系统分页
  7. 福建师范计算机应用基础作业,福建师范大学《计算机应用基础》在线作业一答案.docx...
  8. 高性能密码适用性分析
  9. qcloud windows rtx cpu 100%定位
  10. 转DICOM学习笔记
  11. 房地产前期投资阶段及启动阶段目标成本形成过程
  12. 什么是镜像?什么是虚拟光驱?
  13. smartSVN 新建仓库
  14. CSS3 使用@font-face引入字体的兼容性方案及优化
  15. 中国铸造机械行业市场规模及未来发展趋势
  16. Win10,Ubuntu双系统,格式化Ubuntu系统分区后启动问题
  17. 台式计算机如何取消屏幕密码,电脑屏幕密码如何取消
  18. html 使用 思源字体_Flutter使用思源字体
  19. 【游戏开发】关于Direct X(一)
  20. 创建一个angular7加GN-ZORRO的工程

热门文章

  1. 【大数据】整理-政务数据管理能力指数(GDMI)评估指标体系
  2. “开放赋能”, 趣拿由“零售商”升级为“零售服务商”
  3. Excel分段求平均值
  4. 小陈老师、雪人 HRBUST - 1176(优先队列+)
  5. 小陈java学习笔记0803
  6. 『Python基础』函数
  7. PS学习-风光照片综合处理(二)--湛蓝雪山
  8. PERL XS tutorial
  9. 产业洞察:4成云计算企业落地北京,资本加持之下形成良好应用生态
  10. 学习笔记_ncl_读取nc文件中的变量_制作nc文件的方法