Qt结合GLSL贴出纹理(一、采用原生OpenGL API)

时间:2023-02-02 00:06:29

Qt提供QOpenGLShaderProgram这种类来完成GLSL操作,同时也支持原生的OpenglAPI。在接下来的两篇博客里,我将分别介绍如何用QOpenGLShaderProgram来贴出纹理,以及如何用原生的OpenglAPI贴出纹理。这篇博客介绍的是如何利用原生的OpenglAPI贴纹理:不论是顶点数据的传值,还是纹理的传值,都在GLSL里留下显式的接口变量。

pro文件:

#-------------------------------------------------
#
# Project created by QtCreator 2018-02-09T21:30:32
#
#-------------------------------------------------

QT += core gui opengl

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = shader1
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0


SOURCES += \
main.cpp \
mainwindow.cpp

HEADERS += \
mainwindow.h
LIBS += -lopengl32 -lGLU32

h文件:

#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QOpenGLWidget>#include <QOpenGLFunctions>class MainWindow : public QOpenGLWidget, protected QOpenGLFunctions{    Q_OBJECTpublic:    MainWindow(QWidget *parent = 0);    ~MainWindow();    GLuint              m_uiTexID;    GLuint              m_uiProgram;    GLuint              m_uiVertShader;    GLuint              m_uiFragShader;    GLuint              m_uiMatrixHandle;    GLuint              m_uiVerticesHandle;    GLfloat       *     m_pVertices;    unsigned char *     pLoadTex(char * Image, unsigned long & bWidth, unsigned long & bHeight);protected:    void        initializeGL();    void        paintGL();    void        resizeGL(int, int);};#endif // MAINWINDOW_H

cpp文件:

#include "mainwindow.h"#include <QDir>#include <gl/GLU.H>#include <QMatrix4x4>#include <QDebug>#if !defined(DEG2RAD)#define DEG2RAD (3.1415926 / 180)#endifMainWindow::MainWindow(QWidget *parent)    : QOpenGLWidget(parent){}MainWindow::~MainWindow(){    glDeleteTextures(1, &m_uiTexID);    delete [] m_pVertices;}void MainWindow::initializeGL(){    initializeOpenGLFunctions();    //载入纹理    unsigned long bWidth = 0;    unsigned long bHeight = 0;    QString qstrPath = QDir::currentPath();    qstrPath += "/earth.bmp";    unsigned char * pData = pLoadTex(qstrPath.toLatin1().data(), bWidth, bHeight);    //准备纹理    glActiveTexture(GL_TEXTURE0);    glGenTextures(1, &m_uiTexID);    glEnable(GL_TEXTURE_2D);    glBindTexture(GL_TEXTURE_2D, m_uiTexID);    //这下面的两句是必要的,否则在绘制区的像素数和纹理的像素数不等时,图案不能正常显示    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, bWidth, bHeight,                          GL_BGR_EXT, GL_UNSIGNED_BYTE, pData);    glDisable(GL_TEXTURE_2D);    free(pData);    const char * pSrcVert= "#version 300 es\n"            "in vec3 pos;\n"            "out vec2 texCoord;\n"            "uniform mat4 mat4MVP;\n"            "void main()\n"            "{\n"            "    gl_Position = mat4MVP * vec4(pos, 1.0);\n"            "    texCoord = pos.xy;\n"            "}\n";    m_uiVertShader = glCreateShader(GL_VERTEX_SHADER);    glShaderSource(m_uiVertShader, 1, (const char **)&pSrcVert, NULL);    glCompileShader(m_uiVertShader);    GLint compiled = 0;    glGetShaderiv(m_uiVertShader,GL_COMPILE_STATUS,&compiled);    if (!compiled)    {        // Get the info log for compilation failure        GLint infoLen = 0;        glGetShaderiv(m_uiVertShader,GL_INFO_LOG_LENGTH, &infoLen);        if (infoLen)        {          char* buf = (char*) malloc(infoLen);          if (buf)          {            glGetShaderInfoLog(m_uiVertShader, infoLen, NULL, buf);            qDebug()<<"Could not compile shader %s:"<< buf;            free(buf);          }        }        // Delete the shader program        glDeleteShader(m_uiVertShader);        m_uiVertShader = 0;     }    const char * pSrcFrag= "#version 300 es\n"            "out vec4 color;\n"            "in vec2 texCoord;\n"            "uniform sampler2D Tex\n;"            "void main()\n"            "{\n"            "    color = texture(Tex, texCoord);\n"            "}\n";    m_uiFragShader = glCreateShader(GL_FRAGMENT_SHADER);    glShaderSource(m_uiFragShader, 1, (const char **)&pSrcFrag, NULL);    glCompileShader(m_uiFragShader);    compiled = 0;    glGetShaderiv(m_uiFragShader,GL_COMPILE_STATUS,&compiled);    if (!compiled)    {        // Get the info log for compilation failure        GLint infoLen = 0;        glGetShaderiv(m_uiFragShader,GL_INFO_LOG_LENGTH, &infoLen);        if (infoLen)        {          char* buf = (char*) malloc(infoLen);          if (buf)          {            glGetShaderInfoLog(m_uiFragShader, infoLen, NULL, buf);            qDebug()<<"Could not compile frag shader %s:"<< buf;            free(buf);          }        }        // Delete the shader program        glDeleteShader(m_uiFragShader);        m_uiFragShader = 0;     }    m_uiProgram = glCreateProgram();    glAttachShader(m_uiProgram, m_uiVertShader);    glAttachShader(m_uiProgram, m_uiFragShader);    glLinkProgram(m_uiProgram);    GLint status;    //获取链接状态    glGetProgramiv(m_uiProgram, GL_LINK_STATUS, &status);    //如果链接失败,打印日志信息    if (status == GL_FALSE)    {        GLint infoLogLength;        glGetProgramiv(m_uiProgram, GL_INFO_LOG_LENGTH, &infoLogLength);        GLchar *strInfoLog = new GLchar[infoLogLength + 1];        glGetProgramInfoLog(m_uiProgram, infoLogLength, NULL, strInfoLog);        qDebug()<<"Linker failure: %s\n"<<strInfoLog;        delete[] strInfoLog;    }    //给顶点赋值    GLfloat arrVertices[18] = {0.0, 1.0, 0.0,                              0.0, 0.0, 0.0,                              1.0, 0.0, 0.0,                              1.0, 0.0, 0.0,                              1.0, 1.0, 0.0,                              0.0, 1.0, 0.0};    m_pVertices = new GLfloat[18];    memcpy(m_pVertices, arrVertices, 18 * sizeof(GLfloat));    m_uiVerticesHandle = glGetAttribLocation(m_uiProgram, "pos");    glUseProgram(m_uiProgram);    //给纹理赋值的步骤可以放在initializeGL()里面(glUseProgram之后),也可以放在paintGL()里面    glUniform1i(glGetUniformLocation(m_uiProgram, "Tex"), /*m_uiTexID*/0);    glEnable(GL_DEPTH_TEST);    glClearColor(0,0,0,1);}void MainWindow::paintGL(){    glClear(GL_COLOR_BUFFER_BIT);    //给矩阵赋值的步骤可以放在initializeGL()里面(glUseProgram之后),也可以放在paintGL()里面    m_uiMatrixHandle = glGetUniformLocation(m_uiProgram, "mat4MVP");    QMatrix4x4 m;    //m.lookAt(eye, center, up);    m.translate(-0.5f, 0.0f, 0.0f);    m.ortho(-1.0f, +1.0f, -1.0f, 1.0f, -4.0f, 15.0f);    glUniformMatrix4fv(m_uiMatrixHandle,  1, GL_FALSE,  m.data());    //绘制过程。绘制过程中,必须保持glBindTexture和glEnable(GL_TEXTURE_2D)围在最外围,否则纹理画不出来    glBindTexture(GL_TEXTURE_2D, m_uiTexID);    glEnable(GL_TEXTURE_2D);    //给顶点 赋值    glEnableVertexAttribArray(m_uiVerticesHandle);//    glVertexAttribPointer(m_uiVerticesHandle, 3/*坐标值有3个分量*/, GL_FLOAT,//                          GL_FALSE/*不要归一化到0,1区间*/, 0/*stride*/, (GLvoid *)m_pVertices);    glVertexAttribPointer(m_uiVerticesHandle, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)m_pVertices);    glDrawArrays(GL_TRIANGLES, 0, 6);    glDisableVertexAttribArray(m_uiVerticesHandle);    glBindTexture(GL_TEXTURE_2D, 0);    glDisable(GL_TEXTURE_2D);}void MainWindow::resizeGL(int width, int height){    glViewport(0,0,width,height);    /*glMatrixMode(GL_PROJECTION);    glLoadIdentity();    glOrtho(-50.0, 50.0, -50.0, 50.0, -50.0, 50.0);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();    gluLookAt(60,0,0,0,0,0,0,0,1);*/}unsigned char * MainWindow::pLoadTex(char * Image, unsigned long & bWidth, unsigned long & bHeight){    FILE* img = NULL;    img = fopen(Image, "rb");    DWORD size = 0;    fseek(img,18,SEEK_SET);    fread(&bWidth,4,1,img);    fread(&bHeight,4,1,img);    fseek(img,0,SEEK_END);    size = ftell(img) - 54;    unsigned char *data = (unsigned char*)malloc(size);    fseek(img,54,SEEK_SET);    // image data    fread(data,size,1,img);    fclose(img);    return data;}

结果:

怪异的结果--一开始显示的是黑屏。但是将窗口最小化之后,再弹出就看到纹理了。现在还不知道原因,但是在下一篇博客里,利用QOpenGLShaderProgram可以避免这个情况。

Qt结合GLSL贴出纹理(一、采用原生OpenGL API)

Qt结合GLSL贴出纹理(一、采用原生OpenGL API)