目录
- 1, 画一个变色三角形
1, 画一个变色三角形
#include"MyOpenGLWidget.h"#include<QSurfaceFormat>#include<QDebug>#include<QTimer>#include<QtMath>unsigned intVBO;unsigned intVAO;//顶点坐标float vertices[]={-0.5f,-0.5f,0.0f,// 左下角0.5f,-0.5f,0.0f,// 右下角0.0f,0.5f,0.0f// 顶部};constchar*vertexShaderSource="#version 330 core\n""layout (location = 0) in vec3 aPos;\n""void main()\n""{\n""gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n""}\0";constchar*fragmentShaderSource="#version 330 core\n""out vec4 FragColor;\n""uniform vec4 ourColor;\n"// CPU 端每帧传入的颜色"void main()\n""{\n""FragColor = ourColor;\n""}\0";unsigned int shaderProgram;MyOpenGLWidget::MyOpenGLWidget(QWidget*parent):QOpenGLWidget(parent){// 关键:请求 OpenGL 3.3 Core Profile 上下文// 否则默认上下文版本可能低于3.3,导致 #version 330 core 着色器编译失败QSurfaceFormat format;format.setVersion(3,3);format.setProfile(QSurfaceFormat::CoreProfile);setFormat(format);// 定时器驱动重绘,让 paintGL 持续被调用,形成颜色动画QTimer*timer=newQTimer(this);connect(timer,&QTimer::timeout,this,[this](){update();});timer->start(16);// 约 60 FPS}MyOpenGLWidget::~MyOpenGLWidget(){}voidMyOpenGLWidget::initializeGL(){// 初始化当前 OpenGL 上下文的函数指针// QOpenGLFunctions_3_3_Core::initializeOpenGLFunctions()// 如果上下文不是 3.3 Core,会返回 falsebool ok=initializeOpenGLFunctions();qDebug()<<"initializeOpenGLFunctions:"<<ok;glClearColor(0.0f,0.0f,0.0f,1.0f);m_elapsedTimer.start();// 开始计时,作为 uniform 颜色的时间基准// VAO:保存顶点属性配置信息(怎么解析VBO里的数据)// VBO:GPU显存缓冲区,用来存放顶点原始坐标数据glGenVertexArrays(1,&VAO);// 生成1个顶点数组对象VAO,把返回的ID存入变量VAOglGenBuffers(1,&VBO);// 生成1个顶点缓冲对象VBO,把返回的ID存入变量VBOglBindVertexArray(VAO);// 绑定VAO到当前上下文,之后所有顶点属性配置都会记录进这个VAOglBindBuffer(GL_ARRAY_BUFFER,VBO);// 绑定VBO到当前上下文,之后所有顶点属性配置都会记录进这个VBO//将数据传入显存glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);// 把顶点数据复制到当前绑定到的 VBO//告知显卡如何解析glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);//开启 VAO 属性glEnableVertexAttribArray(0);glBindVertexArray(0);glBindBuffer(GL_ARRAY_BUFFER,0);//编译顶点着色器unsigned int vertexShader=glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader,1,&vertexShaderSource,NULL);glCompileShader(vertexShader);//编译片段着色器unsigned int fragmentShader=glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader,1,&fragmentShaderSource,NULL);glCompileShader(fragmentShader);//link shadersshaderProgram=glCreateProgram();glAttachShader(shaderProgram,vertexShader);glAttachShader(shaderProgram,fragmentShader);glLinkProgram(shaderProgram);// 链接成功后可以删除着色器对象glDeleteShader(vertexShader);glDeleteShader(fragmentShader);}voidMyOpenGLWidget::resizeGL(int w,int h){// 用像素尺寸设置视口,兼容高 DPI 缩放constqreal dpr=devicePixelRatioF();constint pw=static_cast<int>(w*dpr);constint ph=static_cast<int>(h*dpr);glViewport(0,0,pw,ph);}voidMyOpenGLWidget::paintGL(){// 清屏glClear(GL_COLOR_BUFFER_BIT);// 关键:每帧都要重新绑定着色器程序,因为 Qt 可能在 paintGL 之间重置 OpenGL 状态glUseProgram(shaderProgram);// 通过 uniform 设置随时间变化的颜色:// 用正弦函数把 [0, +∞) 的时间映射到 [0, 1] 的颜色分量,// 三个分量错开相位,颜色会平滑地循环变化float timeValue=m_elapsedTimer.elapsed()/1000.0f;// 秒float red=qSin(timeValue)/2.0f+0.5f;float green=qSin(timeValue+2.0f)/2.0f+0.5f;float blue=qSin(timeValue+4.0f)/2.0f+0.5f;// 查询 uniform 变量 "ourColor" 的位置,并传入新颜色// 注意:必须先 glUseProgram,再设置 uniformint vertexColorLocation=glGetUniformLocation(shaderProgram,"ourColor");glUniform4f(vertexColorLocation,red,green,blue,1.0f);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES,0,3);}fragmentShaderSource 这个变量绑定这一段 GLSL 程序
要想实现渐变三角形,就需要 glUniform4f 程序不断地从外部传入变量给
GLSL 的 ourColor 变量来实现渐变三角形。
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, this { update(); });
timer->start(16); // 约 60 FPS
然后开启这个定时器 不断地调用 update() 函数就可以实现渐变三角形了。