压缩纹理与普通纹理的区别是,占用的内存空间变小了;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);
}
到此结束。