1. 程式人生 > >qt opengl 壓縮紋理

qt opengl 壓縮紋理

    壓縮紋理與普通紋理的區別是,佔用的記憶體空間變小了;es 2.0 es3.0都支援ETC1。es 3.0支援ETC2。ETC2支援帶有透明通道的圖片,ETC1不支援透明通道。我這裡使用的是ETC1,png、jpg或其它格式轉換為ETC1的pkm格式壓縮圖片,可以用網上下載的工具。

     其渲染器實現非常簡單,和渲染一幀普通圖片,流程大致相同;只是在載入紋理的時候要設定紋理格式,並載入壓縮後的資料。

其實現如下

#ifndef ETCRENDER_H
#define ETCRENDER_H

#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
class EtcRender
{
public:
    EtcRender() = default;
    void initsize(QString pkmFilePath);
    void render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix,QMatrix4x4 &vMatrix,QMatrix4x4 &mMatrix);

private:
    QOpenGLShaderProgram program_;
    QOpenGLBuffer vbo_;
    QOpenGLTexture *texture_{nullptr};
};

#endif // ETCRENDER_H

#include <QFile>
#include "etcrender.h"

void EtcRender::initsize(QString pkmFilePath)
{
    program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");
    program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");
    program_.link();

#if 1 //設定格式並載入壓縮後的pkm資料
    texture_ = new QOpenGLTexture(QOpenGLTexture::Target2D);
    texture_->setFormat(QOpenGLTexture::RGB8_ETC1);
    QFile file(pkmFilePath);
    if(file.open(QIODevice::ReadOnly)){
        QByteArray arr = file.readAll();
        texture_->setCompressedData(0,0,arr.size(),arr.data());
    }
#else
    texture_ = new QOpenGLTexture(QImage("sample.jpg"));
#endif
    GLfloat points[]{
    -1.0,-1.0,0.0,
    -1.0,+1.0,0.0,
    +1.0,+1.0,0.0,
    +1.0,-1.0,0.0,

    0.0,+1.0,
    0.0,0.0,
    +1.0,0.0,
    +1.0,+1.0
    };
    vbo_.create();
    vbo_.bind();
    vbo_.allocate(points,sizeof(points));
}

void EtcRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix)
{
    f->glDisable(GL_CULL_FACE);
    f->glDisable(GL_DEPTH_TEST);
   //和前面文章一樣,繫結紋理,載入資料,然後繪製
    program_.bind();
    vbo_.bind();
    f->glActiveTexture(GL_TEXTURE0 + 0);
    program_.setUniformValue("sTextures",0);
    program_.setUniformValue("uPMatrix",pMatrix);
    program_.setUniformValue("uVMatrix",vMatrix);
    program_.setUniformValue("uMMatrix",mMatrix);
    program_.enableAttributeArray(0);
    program_.enableAttributeArray(1);
    program_.setAttributeBuffer(0,GL_FLOAT,0,3,3 * sizeof(GLfloat));
    program_.setAttributeBuffer(1,GL_FLOAT,3 * 4 * sizeof(GLfloat),2,2 *sizeof(GLfloat));

    texture_->bind(0);
    f->glDrawArrays(GL_TRIANGLE_FAN,0,4);

    program_.disableAttributeArray(0);
    program_.disableAttributeArray(1);
    texture_->release();
    vbo_.release();
    program_.release();
}

 其在widget中的使用也非常簡單,如下

#ifndef WIDGET_H
#define WIDGET_H

#include <QOpenGLWidget>
#include "etcrender.h"
class Widget : public QOpenGLWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

protected:
    void initializeGL() override;
    void resizeGL(int w, int h) override;
    void paintGL()override;

private:
    EtcRender render_;
    QMatrix4x4 pMatrix_;
    QVector3D cameraLocation_;
};

#endif // WIDGET_H
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QOpenGLWidget(parent)
{
}

Widget::~Widget()
{

}

void Widget::initializeGL()
{
    render_.initsize("bbt.pkm");
    //設定視角
    cameraLocation_.setX(0);
    cameraLocation_.setY(0);
    cameraLocation_.setZ(2);
}

void Widget::resizeGL(int w, int h)
{
    pMatrix_.setToIdentity();
    pMatrix_.perspective(45,float(w)/h,0.01f,100.0f);
}

void Widget::paintGL()
{
    QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
    f->glClearColor(0.0f,0.0f,0.0f,1.0f);
    f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    QMatrix4x4 view;
    view.lookAt(cameraLocation_,QVector3D{0.0,0.0,0.0},QVector3D{0.0,1.0,0.0});

    QMatrix4x4 model; //不經過任何轉換
    render_.render(f,pMatrix_,view,model);
}

其shader如下

#version 330
uniform mat4 uPMatrix,uVMatrix,uMMatrix;
layout (location = 0) in vec3 aPositin;
layout (location = 1) in vec2 aTextureCoord;
smooth out vec2 vTextureCoord;

void main(void)
{
    gl_Position = uPMatrix * uVMatrix * uMMatrix * vec4(aPositin,1);
    vTextureCoord = aTextureCoord;
}
#version 330
uniform sampler2D sTextures;
in vec2 vTextureCoord;
out vec4 fragColor;

void main(void)
{
    fragColor = texture2D(sTextures,vTextureCoord);
}

      到此結束。