2d纹理数组就是用一个纹理数组类型的变量保存数个纹理,这样就避免了使用多个单个的纹理对象。这再批处理一系列相同大小的纹理时,非常有用,我这里用到的场景是在点精灵中使用纹理数组使得每个精灵纹理上不同的图案。
我用的图片有16张,当顶点为16个时,效果如下
可以看到刚好一个图案一个顶点,当顶点大于16个时如下
可以看到,当大于纹理数组个数的顶点时,超出的部分会重重其中一个纹理,至于重得的这个纹理未做研究
其渲染器实现如下
#ifndef TEXTURE2DARRAYRENDER_H
#define TEXTURE2DARRAYRENDER_H
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLExtraFunctions>
class Texture2DArrayRender
{
public:
Texture2DArrayRender() = default;
void initsize(int pointCount,QVector<QImage> &imgs,int width,int height);
void render(QOpenGLExtraFunctions *f,QMatrix4x4 &pMatrix,QMatrix4x4 &vMatrix,QMatrix4x4 &mMatrix);
private:
QOpenGLShaderProgram program_;
QOpenGLTexture *texture_{nullptr};
QOpenGLBuffer vbo_;
};
#endif // TEXTURE2DARRAYRENDER_H
#include <random>
#include "texture2darrayrender.h"
void Texture2DArrayRender::initsize(int pointCount, QVector<QImage> &imgs, int width, int height)
{
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");
program_.link();
texture_ = new QOpenGLTexture(QOpenGLTexture::Target2DArray);
texture_->create();
texture_->setSize(width,height);//设置宽、高
texture_->setLayers(imgs.count()); //设置个数
texture_->setFormat(QOpenGLTexture::RGB8_UNorm);
texture_->allocateStorage();
for(int i = 0; i < imgs.count(); i++){
QImage cvtImg(imgs.at(i).convertToFormat(QImage::Format_RGB888));
texture_->setData(0,i,QOpenGLTexture::RGB,QOpenGLTexture::UInt8,cvtImg.constBits()); //设置每层的数据
}
texture_->setMinMagFilters(QOpenGLTexture::Nearest,QOpenGLTexture::Nearest);
texture_->setWrapMode(QOpenGLTexture::ClampToEdge);
//生成顶点
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> dis(-1.0,1.0);
QVector<GLfloat> pointVec;
for(int i = 0; i < pointCount * 3; i++){
pointVec << dis(gen);
}
vbo_.create();
vbo_.bind();
vbo_.allocate(pointVec.data(),pointVec.count() * sizeof GLfloat);
}
void Texture2DArrayRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix)
{
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_BLEND);
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_POINT_SPRITE);
f->glEnable(GL_PROGRAM_POINT_SIZE);
f->glEnable(GL_TEXTURE_2D_ARRAY); //默认是开启的
program_.bind();
vbo_.bind();
f->glActiveTexture(GL_TEXTURE0 + 0);
program_.setUniformValue("pMatrix",pMatrix);
program_.setUniformValue("vMatrix",vMatrix);
program_.setUniformValue("mMatrix",mMatrix);
program_.setUniformValue("sTexture",0);
program_.enableAttributeArray(0);
program_.setAttributeBuffer(0,GL_FLOAT,0,3,3 * sizeof GLfloat);
texture_->bind(0);
f->glDrawArrays(GL_POINTS,0,vbo_.size() / (3 * sizeof (GLfloat)));
program_.disableAttributeArray(0);
texture_->release();
vbo_.release();
f->glDisable(GL_DEPTH_TEST);
f->glDisable(GL_BLEND);
f->glDisable(GL_DEPTH_TEST);
f->glDisable(GL_POINT_SPRITE);
f->glDisable(GL_PROGRAM_POINT_SIZE);
f->glDisable(GL_TEXTURE_2D_ARRAY);
}
基shader实现如下
#version 330
uniform mat4 pMatrix,vMatrix,mMatrix;
layout (location = 0) in vec3 aPosition;
out float vid;
void main(void)
{
gl_Position = pMatrix * vMatrix *mMatrix * vec4(aPosition ,1);
gl_PointSize = 64.0;
vid = float(gl_VertexID);
}
#version 330
uniform sampler2DArray sTexture;
in float vid;
out vec4 fragColor;
void main(void)
{
vec3 texCoord = vec3(gl_PointCoord.st,vid);
fragColor = texture(sTexture,texCoord);
}
使用方法和前面一样,根据参数传入数据就可以了
#ifndef WIDGET_H
#define WIDGET_H
#include <QOpenGLWidget>
#include "texture2darrayrender.h"
class Widget : public QOpenGLWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void resizeGL(int w,int h) override;
void paintGL() override;
void initializeGL() override;
private:
Texture2DArrayRender render_;
QMatrix4x4 pMatrix_;
QVector3D camera_;
};
#endif // WIDGET_H
#include <QDir>
#include <QDebug>
#include "widget.h"
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent)
{
}
Widget::~Widget()
{
}
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 vMatrix;
vMatrix.lookAt(camera_,QVector3D(0.0,0.0,0.0),QVector3D(0.0,1.0,0.0));
QMatrix4x4 mMatrix;
render_.render(f,pMatrix_,vMatrix,mMatrix);
}
void Widget::initializeGL()
{
QVector<QImage> imgs;
QDir imgDir(".");
foreach (const QFileInfo &fileInfor, imgDir.entryInfoList(QStringList() << "*.png",QDir::Files)) {
imgs << QImage(fileInfor.absoluteFilePath());
}
render_.initsize(20,imgs,128,128);
camera_.setX(0);
camera_.setY(0);
camera_.setZ(3);
}
至此结束