Browse Source

V0.7.11
1、重新修改了RGBA着色器代码,将创建纹理的函数从父类剥离出来

Apple 2 weeks ago
parent
commit
732499b359

+ 75 - 79
demo/VideoPlayerGL/GLShader/ShaderBase.cpp

@@ -115,108 +115,107 @@ bool ShaderBase::compileShader()
 }
 
 /**
- * @brief 初始化纹理,返回值是生成的纹理ID
+ * @brief 创建纹理,可以显式的指定纹理单元编号,返回纹理单元编号,创建失败则返回的是
  * 
- * @param imageFile 纹理图片路径
- * @param uniformName 纹理对应的uniform变量名称
- * @return true 
- * @return false 
+ * @param uniformName 
+ * @param textureUnit 如果不指定或者小于0,则会自动分配纹理单元编号
+ * @return int -1,创建失败,>0,创建成功
  */
-bool ShaderBase::createTexture(const QString &imageFile, const QString uniformName)
+int ShaderBase::createTexture(const QString uniformName, int textureUnit)
 {
-    bool isExist = false;
-    for(auto& it : m_listTexture) 
+    GLint maxTextureUnits = 0;
+    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+    if(textureUnit > maxTextureUnits) 
     {
-        if(it.first == uniformName) 
+        SPDLOG_ERROR("纹理单元编号:{}已超过支持的最大单元数目:{}", textureUnit, maxTextureUnits);
+        return -1;
+    }
+    /* 制定了单元编号,先查重 */
+    int texUnit = textureUnit;
+    if(texUnit >= 0)
+    {
+        for(auto it = m_mapTexture.begin(); it != m_mapTexture.end(); ++it) 
         {
-            QOpenGLTexture* texture = it.second;
-            if (texture != nullptr) {
-                texture->destroy();
-                delete texture;
-                texture = nullptr;
+            if(it.key() == texUnit) 
+            {
+                if(it->first == uniformName) 
+                {
+                    SPDLOG_WARN("纹理单元编号:{},名称:{} 已存在", texUnit, uniformName.toStdString());
+                    return texUnit;
+                } else 
+                {
+                    /* 删除该纹理单元 */
+                    SPDLOG_WARN("纹理单元编号:{},名称:{} 已存在,将被替换为名称:{}", texUnit, it->first.toStdString(), uniformName.toStdString());
+                    if(it->second != nullptr) 
+                    {
+                        it->second->destroy();
+                        delete it->second;
+                        it->second = nullptr;
+                    }
+                    m_mapTexture.erase(it); // 删除该纹理单元
+                    break; // 退出循环
+                }
             }
-            /* 纹理已存在,删除纹理 */
-            m_listTexture.removeOne(it);
-            isExist = true;
-            break;
         }
-    }
-    if(!isExist)
+    }else 
     {
-        /* 纹理图片不存在,检查是否已经超过最大的纹理数目 */
-        int maxTextureUnits = 0;
-        // maxTextureUnits 就是当前环境支持的最大纹理单元数
-        glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
-
-        if (m_listTexture.size() >= maxTextureUnits) {
-            SPDLOG_ERROR("纹理图片数量超过最大限制");
-            return false;
+        /* 没有分配编号,手动分配 */
+        texUnit = 0;
+        for(int i = 0; i < m_mapTexture.size(); i++)
+        {
+            if(!m_mapTexture.contains(i))
+            {
+                texUnit = i;
+                break;
+            }
         }
     }
-    
-    /* 加载图片 */
-    QImage image;
-    image.load(imageFile);
-    if (image.isNull()) {
-        SPDLOG_ERROR("Failed to load image: {}", imageFile.toStdString());
-        return false;
-    }
-    /* 将图片转换为RGBA格式 */
-    image = image.convertToFormat(QImage::Format_RGBA8888);
-    /* 这里要垂直翻转 */
-    // image = image.mirrored(false, true);
 
     QOpenGLTexture* texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
-    texture->setSize(image.width(), image.height(), 1); // 设置纹理大小
-    texture->setFormat(QOpenGLTexture::RGBA8_UNorm); // 设置纹理格式
-    texture->allocateStorage(); // 分配纹理存储空间
-    texture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.bits()); // 设置纹理数据
     /* 设置纹理参数 */
     texture->setWrapMode(QOpenGLTexture::Repeat); // S轴环绕方式
     texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); // 纹理缩小过滤方式
     texture->setMagnificationFilter(QOpenGLTexture::Linear); // 纹理放大过滤方式
     
-    
-    texture->generateMipMaps(); // 生成多级渐远纹理
 
     printGLerror("ShaderBase::createTextureFile");
     /* 将纹理存储到数组中 */
-    m_listTexture.push_back(QPair<QString, QOpenGLTexture*>(uniformName, texture));
+    m_mapTexture.insert(texUnit, QPair<QString, QOpenGLTexture*>(uniformName, texture));
 
-    return true;
+    return texUnit;
 }
 
-/* 初始化纹理,直接传入图片 */
-bool ShaderBase::createTexture(const QImage &image, const QString uniformName)
-{
-    if(image.isNull()) {
-        SPDLOG_WARN("Texture Image is null");
-        return false;
-    }
-    QOpenGLTexture* texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
-    texture->setSize(image.width(), image.height(), 1); // 设置纹理大小
-    texture->setFormat(QOpenGLTexture::RGBA8_UNorm); // 设置纹理格式
-    texture->allocateStorage(); // 分配纹理存储空间
-    texture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.convertToFormat(QImage::Format_RGBA8888).bits()); // 设置纹理数据
-    /* 设置纹理参数 */
-    texture->setWrapMode(QOpenGLTexture::Repeat); // S轴环绕方式
-    texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); // 纹理缩小过滤方式
-    texture->setMagnificationFilter(QOpenGLTexture::Linear); // 纹理放大过滤方式
+// /* 初始化纹理,直接传入图片 */
+// bool ShaderBase::createTexture(const QImage &image, const QString uniformName)
+// {
+//     if(image.isNull()) {
+//         SPDLOG_WARN("Texture Image is null");
+//         return false;
+//     }
+//     QOpenGLTexture* texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+//     texture->setSize(image.width(), image.height(), 1); // 设置纹理大小
+//     texture->setFormat(QOpenGLTexture::RGBA8_UNorm); // 设置纹理格式
+//     texture->allocateStorage(); // 分配纹理存储空间
+//     texture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.convertToFormat(QImage::Format_RGBA8888).bits()); // 设置纹理数据
+//     /* 设置纹理参数 */
+//     texture->setWrapMode(QOpenGLTexture::Repeat); // S轴环绕方式
+//     texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); // 纹理缩小过滤方式
+//     texture->setMagnificationFilter(QOpenGLTexture::Linear); // 纹理放大过滤方式
     
     
-    texture->generateMipMaps(); // 生成多级渐远纹理
+//     texture->generateMipMaps(); // 生成多级渐远纹理
 
-    printGLerror("ShaderBase::createTextureImage");
-    /* 将纹理存储到数组中 */
-    m_listTexture.push_back(QPair<QString, QOpenGLTexture*>(uniformName, texture));
+//     printGLerror("ShaderBase::createTextureImage");
+//     /* 将纹理存储到数组中 */
+//     m_listTexture.push_back(QPair<QString, QOpenGLTexture*>(uniformName, texture));
 
-    return true;
-}
+//     return true;
+// }
 
 /* 清空纹理 */
 void ShaderBase::clearTexture()
 {
-    for(auto& it : m_listTexture) 
+    for(auto& it : m_mapTexture) 
     {
         if(it.second != nullptr) 
         {
@@ -225,7 +224,7 @@ void ShaderBase::clearTexture()
             it.second = nullptr;
         }
     }
-    m_listTexture.clear();
+    m_mapTexture.clear();
 }
 
 /* 使用着色器 */
@@ -238,12 +237,11 @@ void ShaderBase::useShader()
     /* 使用着色器程序 */
     m_shaderProgramObj->bind();
     /* 使用纹理 */
-    if(m_listTexture.size() > 0) 
+    if(m_mapTexture.size() > 0) 
     {
-        int currentTextureUnit = 0;
-        for (auto it = m_listTexture.begin(); it != m_listTexture.end(); ++it) 
+        for (auto it = m_mapTexture.begin(); it != m_mapTexture.end(); ++it) 
         {
-            it->second->bind(currentTextureUnit);
+            it->second->bind(it.key());
             /* 绑定纹理 */
             int location = m_shaderProgramObj->uniformLocation(it->first);
             if (location < 0) {
@@ -251,9 +249,7 @@ void ShaderBase::useShader()
                 continue;
             }
             /* 设置纹理单元 */
-            m_shaderProgramObj->setUniformValue(location, currentTextureUnit); 
-
-            currentTextureUnit++;
+            m_shaderProgramObj->setUniformValue(location, it.key()); 
         }
     }
 }

+ 4 - 5
demo/VideoPlayerGL/GLShader/ShaderBase.h

@@ -27,10 +27,8 @@ public:
     virtual bool loadShaderCode(const QString &vertexShaderFile, const QString &fragmentShaderFile);
     /* 编译着色器程序 */
     virtual bool compileShader();
-    /* 初始化纹理,返回值是生成的纹理ID */
-    virtual bool createTexture(const QString &imageFile, const QString uniformName);
-    /* 初始化纹理,直接传入图片 */
-    virtual bool createTexture(const QImage &image, const QString uniformName);
+    /* 创建纹理,可以显式的指定纹理单元编号,返回纹理单元编号,创建失败则返回的是-1 */
+    virtual int createTexture(const QString uniformName, int textureUnit = -1);
     /* 清空纹理 */
     virtual void clearTexture();
 
@@ -47,7 +45,8 @@ protected:
     QByteArray m_fragmentShaderCode;                        /* 片段着色器文件 */
     QOpenGLShaderProgram* m_shaderProgramObj = nullptr;     /* 着色器程序对象 */
     
-    QList<QPair<QString, QOpenGLTexture*>> m_listTexture;   /* uniform和纹理的映射 */
+    // QList<QPair<QString, QOpenGLTexture*>> m_listTexture;   /* uniform和纹理的映射 */
+    QMap<int, QPair<QString, QOpenGLTexture*>> m_mapTexture; /* uniform和纹理的映射,int是第几个,与 GL_TEXTURE0 相对应 */
 };
 
 

+ 31 - 0
demo/VideoPlayerGL/GLShader/ShaderRect.cpp

@@ -107,3 +107,34 @@ void ShaderRect::drawShape()
     gl->glBindVertexArray(0); // 解绑VAO
 }
 
+/* 刷新一帧 */
+bool ShaderRect::refreshFrameRGBA(const QImage& image, int textureUnit)
+{
+    if(image.isNull()) {
+        SPDLOG_WARN("Texture Image is null");
+        return false;
+    }
+    QOpenGLTexture* texture = m_mapTexture.find(textureUnit)->second;
+    if(texture == nullptr)
+    {
+        SPDLOG_ERROR("错误的纹理编号:{}", textureUnit);
+        return false;
+    }
+    if(m_lastSize != image.size())
+    {
+        texture->destroy();   // 释放OpenGL资源
+        texture->create();    // 重新创建OpenGL资源
+        texture->setSize(image.width(), image.height(), 1); // 设置纹理大小
+        texture->setFormat(QOpenGLTexture::RGBA8_UNorm); // 设置纹理格式
+        texture->allocateStorage(); // 分配纹理存储空间
+    }
+    m_lastSize = image.size();
+    texture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.bits()); // 设置纹理数据
+
+    texture->generateMipMaps(); // 生成多级渐远纹理
+
+    printGLerror("ShaderRect::refreshFrame");
+
+    return true;
+}
+

+ 3 - 1
demo/VideoPlayerGL/GLShader/ShaderRect.h

@@ -20,12 +20,14 @@ public:
     /* 绘制图形 */
     void drawShape() override;
 
-    
+    /* 刷新一帧 */
+    bool refreshFrameRGBA(const QImage& image, int textureUnit = 0);
 
 private:
     GLuint m_VAO = 0;              // 顶点数组对象的ID
     GLuint m_VBO = 0;              // 顶点缓冲对象的ID
     GLuint m_EBO = 0;              // 索引缓冲对象的ID
+    QSize m_lastSize;               /* 上一张图片的大小 */
 };
 
 

+ 15 - 3
demo/VideoPlayerGL/GLWidget/PlayerGLWidget.cpp

@@ -23,8 +23,14 @@ PlayerGLWidget::~PlayerGLWidget()
 /* 显示RGBA图片 */
 void PlayerGLWidget::showOneRGBAImage(const QImage& image)
 {
-    m_shaderRGBA->clearTexture(); // 清空纹理
-    m_shaderRGBA->createTexture(image, "textureRGBA"); // 创建纹理
+    if(image.format() == QImage::Format_RGBA8888)
+    {
+        m_shaderRGBA->refreshFrameRGBA(image);
+    } else 
+    {
+        QImage imageRGBA = image.convertToFormat(QImage::Format_RGBA8888);
+        m_shaderRGBA->refreshFrameRGBA(imageRGBA);
+    }
 
     m_shaderCurr = m_shaderRGBA; // 设置当前着色器为显示RGBA图片的着色器
     update(); // 更新界面,触发paintGL函数
@@ -42,7 +48,7 @@ void PlayerGLWidget::initializeGL()
 
     m_shaderRGBA->initShape(); // 初始化形状
 
-    /* 初始化着色器 */
+    /* 初始化RGBA着色器 */
     QString vertexShaderFile = ":/shaderCode/vertexShaderRGBA.glsl";
     QString fragmentShaderFile = ":/shaderCode/fragmentShaderRGBA.glsl";
     if (!m_shaderRGBA->loadShaderCode(vertexShaderFile, fragmentShaderFile)) 
@@ -52,6 +58,12 @@ void PlayerGLWidget::initializeGL()
     }
     /* 编译着色器 */
     m_shaderRGBA->compileShader();
+    /* 创建一个纹理对象 */
+    m_textureRGBAUnit = m_shaderRGBA->createTexture("textureRGBA");
+    if(m_textureRGBAUnit < 0)
+    {
+        SPDLOG_ERROR("RGBA着色器创建纹理失败!");
+    }
 
 
     SPDLOG_DEBUG("着色器编译完成");

+ 2 - 1
demo/VideoPlayerGL/GLWidget/PlayerGLWidget.h

@@ -39,7 +39,8 @@ private:
     // GLuint m_VAO1 = 0; // 顶点数组对象的ID
     
     ShaderBase* m_shaderCurr = nullptr;     /* 当前使用的着色器对象 */
-    ShaderBase* m_shaderRGBA = nullptr;     /* 显示RGBA图片的着色器对象 */
+    ShaderRect* m_shaderRGBA = nullptr;     /* 显示RGBA图片的着色器对象 */
+    int m_textureRGBAUnit = -1;
 
 };
 

+ 1 - 1
demo/VideoPlayerGL/shaderCode/fragmentShaderRGBA.glsl

@@ -11,4 +11,4 @@ void main()
 {
     //FragColor = vec4(1,0,0,1);
     FragColor = texture(textureRGBA, TexCoord);
-}
+}