点精灵就是在opengl中画点,在画点的同时指明点的大小,这样点就会变成一个实心的矩形(指明GL_POINT_SMOOTH可能不正确,大体是这个;就会是一个圆)。画每个矩形时,给每个矩形加载一个纹理图,就变成了点精灵;每个纹理坐标从内建变量gl_PointCoord获取。
50个随机点32*32效果图如下
其渲染器实现如下
#ifndef POINTSPRINTRENDER_H
#define POINTSPRINTRENDER_H
#include
#include
#include
#include
class PointSprintRender
{
public:
PointSprintRender() = default;
void initsize(QOpenGLExtraFunctions* f,QImage &textureImg,int pointsCount);//传入f获取最大、最小点精灵大小
void render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix, float pointSize);
private:
QOpenGLShaderProgram program_;
QOpenGLBuffer vbo_;
QOpenGLTexture *texture_{nullptr};
int pointCount_ = 0;
float maxPointSize_=0,minPointSize_=0;
};
#endif // POINTSPRINTRENDER_H
#include
#include
#include
#include "pointsprintrender.h"
void PointSprintRender::initsize(QOpenGLExtraFunctions *f, QImage &textureImg, int pointsCount)
{
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Vertex,"vsrc.vert");
program_.addCacheableShaderFromSourceFile(QOpenGLShader::Fragment,"fsrc.frag");
program_.link();
texture_ = new QOpenGLTexture(textureImg);
texture_->setWrapMode(QOpenGLTexture::DirectionS,QOpenGLTexture::ClampToEdge);
texture_->setWrapMode(QOpenGLTexture::DirectionT,QOpenGLTexture::ClampToEdge);
texture_->setMinMagFilters(QOpenGLTexture::Nearest,QOpenGLTexture::Linear);
pointCount_ = pointsCount;
//随机生成顶点
QVector vertVec;
unsigned seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
// std::random_device rd;
std::mt19937 gen(seed);
std::uniform_real_distribution dis(-1.0,1.0);
for(int i = 0; i < pointCount_ * 3; i++){
vertVec << dis(gen);
}
vbo_.create();
vbo_.bind();
vbo_.allocate(vertVec.data(),vertVec.count() * sizeof(GLfloat));
float pointsSizeRange[2]{0};
f->glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE,pointsSizeRange);
minPointSize_ = pointsSizeRange[0];
maxPointSize_ = pointsSizeRange[1];
qDebug() << minPointSize_ << maxPointSize_;
}
void PointSprintRender::render(QOpenGLExtraFunctions *f, QMatrix4x4 &pMatrix, QMatrix4x4 &vMatrix, QMatrix4x4 &mMatrix,float pointSize)
{
f->glEnable(GL_CULL_FACE);
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_BLEND); //开启混合
f->glEnable(GL_POINT_SPRITE); //开启点精灵模式,使用点块纹理
f->glEnable(GL_PROGRAM_POINT_SIZE); //让顶点程序决定点块大小
program_.bind();
vbo_.bind();
f->glActiveTexture(GL_TEXTURE0 + 0);
program_.setUniformValue("sTexture",0);
program_.setUniformValue("pMatrix",pMatrix);
program_.setUniformValue("vMatrix",vMatrix);
program_.setUniformValue("mMatrix",mMatrix);
program_.setUniformValue("uPointSize",pointSize);
program_.enableAttributeArray(0);
texture_->bind(0);
program_.setAttributeBuffer(0,GL_FLOAT,0,3,3 * sizeof(GLfloat));
f->glDrawArrays(GL_POINTS,0,pointCount_);
program_.disableAttributeArray(0);
texture_->release();
vbo_.release();
program_.release();
f->glDisable(GL_CULL_FACE);
f->glDisable(GL_DEPTH_TEST);
f->glDisable(GL_BLEND);
f->glDisable(GL_POINT_SPRITE);
f->glDisable(GL_PROGRAM_POINT_SIZE);
}
其shader如下
#version 330
uniform mat4 pMatrix,vMatrix,mMatrix;
uniform float uPointSize;
layout (location = 0) in vec3 aPosition;
void main(void)
{
gl_Position = pMatrix * vMatrix * mMatrix * vec4(aPosition, 1);
gl_PointSize = uPointSize; //设置点大小
}
#version 330
uniform sampler2D sTexture;
out vec4 fragColor;
void main(void)
{
vec2 texCoor = gl_PointCoord; //用临时变量保存一下,以保证正常运行。避免出现异常情况
fragColor = texture2D(sTexture, texCoor);
}
使用时传入对应的MVP矩阵坐标,点精灵数量就可以了
#ifndef WIDGET_H
#define WIDGET_H
#include
#include "pointsprintrender.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:
PointSprintRender render_;
QMatrix4x4 pMatrix_;
QVector3D cameraLocation_;
};
#endif // WIDGET_H
#include "widget.h"
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent)
{
}
Widget::~Widget()
{
}
void Widget::initializeGL()
{
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
render_.initsize(f,QImage("fp.png"),50);
cameraLocation_.setX(0);
cameraLocation_.setY(0);
cameraLocation_.setZ(3);
}
void Widget::resizeGL(int w, int h)
{
pMatrix_.setToIdentity();
pMatrix_.perspective(30,float(w)/h,0.01f,50.0f);
}
void Widget::paintGL()
{
QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
f->glClearColor(0.0,0.0,0.0,1.0);
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,32);
}
到此结束