Skip to content

Instantly share code, notes, and snippets.

@kheaactua
Last active February 24, 2017 16:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kheaactua/8e1f78a07fa2ab2ac2e60b0a23444318 to your computer and use it in GitHub Desktop.
Save kheaactua/8e1f78a07fa2ab2ac2e60b0a23444318 to your computer and use it in GitHub Desktop.
Small buffer that contains (and creates) point data that is later read into an OpenGL buffer
#ifndef MYPOINTBUFFER_H_CMWR60UT
#define MYPOINTBUFFER_H_CMWR60UT
#include <QtGui/QOpenGLFunctions>
#include <QVector>
class MyPointBuffer {
public:
MyPointBuffer() {
std::random_device rd;
std::mt19937 gen(rd());
auto randCoord = [&] (const unsigned int sr) {
std::uniform_real_distribution<float> dis(static_cast<int>(-1*sr), static_cast<int>(sr));
return dis(gen);
};
points_.resize(count_ * vertexSize_);
GLfloat* p = points_.data();
for (unsigned int i=0; i<count_*vertexSize_; i++) {
*p++ = randCoord(100);
}
}
auto constData() const -> const GLfloat* {
return points_.constData();
}
auto data() -> GLfloat* {
return points_.data();
}
auto vertexCount() const -> const unsigned int {
return count_;
}
/**
* Read the buffer, return the average value.. This is just to test
* for changes in the data..
*/
auto avg() const -> const float {
float sum = 0;
unsigned int count = 0;
auto raw_data = constData();
for (unsigned int i=0; i<count_; i++) {
auto addr = i * vertexSize_;
count += 3;
sum += raw_data[addr] + raw_data[addr+1] + raw_data[addr+2];
}
return sum/count;
}
/**
* Attempt to read in data from a pointer. Assume same size
*/
auto setData(void* p_start) -> void {
GLfloat* p = points_.data();
memcpy(p, p_start, count_*vertexSize_*sizeof(GLfloat));
}
/**
* Increment every point in the buffer, this will be used to test to
* see if any writes at all were done in the compute shader.
*/
auto inc() -> void {
GLfloat* p = points_.data();
for (unsigned int i=0; i<count_*vertexSize_; i++) {
*p = static_cast<GLfloat>(*p) + 1.0f;
*p = *p + 1;
}
}
QVector<GLfloat> points_;
const unsigned int vertexSize_ = 4;
const unsigned int stride_ = vertexSize_*sizeof(GLfloat);
const unsigned int count_ = 10000u;
};
#endif /* end of include guard: MYPOINTBUFFER_H_CMWR60UT */
/* vim: set ts=4 sw=4 sts=4 expandtab ffs=unix,dos : */
#version 430
uniform float dx;
uniform float dy;
layout(local_size_x = 1024) in;
struct ParticleData
{
vec4 position;
};
// Particles from previous frame
layout (std430, binding = 0) coherent buffer Particles
{
ParticleData particles[];
} data;
void main(void)
{
uint globalId = gl_GlobalInvocationID.x;
// Retrieve current particle from previous frame
ParticleData currentParticle = data.particles[globalId];
// New position = old position + distance traveled over step duration
currentParticle.position[0] = currentParticle.position[0] + dx + 5;
currentParticle.position[1] = currentParticle.position[1] + dy + 5;
// Save updated particle
data.particles[globalId] = currentParticle;
}
// vim: ts=3 sw=3 noet ffs=unix :
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import matt 1.0
Material {
property PointBuffer dataBuffer;
ShaderProgram {
id: computeShader
computeShaderCode: loadSource("qrc:/shaders/pointcloud.comp")
}
ShaderProgram {
id: drawShader
vertexShaderCode: loadSource("qrc:/shaders/pointcloud.vert")
fragmentShaderCode: loadSource("qrc:/shaders/pointcloud.frag")
}
effect: Effect {
techniques: [
Technique {
renderPasses: [
RenderPass {
shaderProgram: computeShader
parameters: [
// Point buffer
Parameter { name: "Particles"; value: dataBuffer }
// Translation/ship movement
, Parameter { name: "dx"; value: -1/60 }
, Parameter { name: "dy"; value: -1/60 }
]
}
] // renderpasses
filterKeys: [
FilterKey { name: "type"; value: "compute" }
]
graphicsApiFilter {
api: GraphicsApiFilter.OpenGL
profile: GraphicsApiFilter.CoreProfile
majorVersion: 4
minorVersion: 3
}
},
Technique {
renderPasses: [
RenderPass {
shaderProgram: drawShader
renderStates: [
PointSize { sizeMode: PointSize.Programmable } // supported since OpenGL 3.2
]
parameters: [
Parameter { name: "pointSize"; value: 0.1 }
// Colour is determined by the square of the point (x,y) position,
// multiplied by this maxDistance
, Parameter { name: "maxDistance"; value: 1/4500 }
]
}
] // renderPasses
filterKeys: [
FilterKey { name: "type"; value: "draw" }
]
graphicsApiFilter {
api: GraphicsApiFilter.OpenGL
profile: GraphicsApiFilter.CoreProfile
majorVersion: 4
minorVersion: 3
}
} // technique
] // techniques
}
}
// vim: ts=3 sw=3 sts=0 noet ffs=unix ft=qml :
#ifndef SQUIRCLE_H
#define SQUIRCLE_H
#include <iostream>
#include <QtQuick/QQuickItem>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLFunctions_4_3_Core>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QtQuick/qquickwindow.h>
#include <QSurfaceFormat>
#include <QRectF>
#include "app/qobjs/MyPointBuffer.h"
class SquircleRenderer : public QObject
, protected QOpenGLFunctions_4_3_Core
{
Q_OBJECT
public:
SquircleRenderer();
~SquircleRenderer();
void setRotx(qreal val) { rotx_ = val; }
void setRoty(qreal val) { roty_ = val; }
void setRotz(qreal val) { rotz_ = val; }
void setNormalizedRect(const QRectF& rect) { rect_ = rect; }
void setWindow(QQuickWindow* window) { window_ = window; }
public slots:
void paint();
private:
auto initializeGL() -> void;
auto compute() -> void;
auto paintGL() -> void;
auto setupVertexAttribs() -> void;
auto setViewport() -> const QSize;
auto getViewportMatrix() -> const QMatrix4x4;
qreal rotx_{0.0f};
qreal roty_{0.0f};
qreal rotz_{0.0f};
QRectF rect_{qreal(0), qreal(0), qreal(1), qreal(1)};
QOpenGLShaderProgram* renderProgram_ = nullptr;
QOpenGLShaderProgram* computeProgram_ = nullptr;
QQuickWindow* window_ = nullptr;
QSurfaceFormat* format_ = nullptr;
MyPointBuffer pointBuffer_;
QOpenGLBuffer pointOpenGLBuffer_{QOpenGLBuffer::VertexBuffer};
QOpenGLVertexArrayObject m_vao;
QOpenGLVertexArrayObject m_vaoC;
int m_projMatrixLoc = 0;
int m_modelViewLoc = 0;
int m_viewportMatrixLoc = 0;
int m_ParticlesLoc = 0;
int m_vertexPositionLoc = 0;
int m_dxLoc = 0;
int m_dyLoc = 0;
void* local_p = NULL;
QMatrix4x4 m_proj;
QMatrix4x4 m_camera;
QMatrix4x4 m_world;
};
class Squircle : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(qreal rotx READ rotx WRITE setRotx NOTIFY rotxChanged)
Q_PROPERTY(qreal roty READ roty WRITE setRoty NOTIFY rotyChanged)
Q_PROPERTY(qreal rotz READ rotz WRITE setRotz NOTIFY rotzChanged)
Q_PROPERTY(QRectF normalizedRect READ normalizedRect WRITE setNormalizedRect NOTIFY normalizedRectChanged)
public:
Squircle();
QRectF normalizedRect() { return rect_; }
void setNormalizedRect(const QRectF& rect) { rect_ = rect; }
auto rotx() -> qreal { return rotx_; }
auto roty() -> qreal { return roty_; }
auto rotz() -> qreal { return rotz_; }
auto setRotx(qreal val) -> void { if (val == rotx_) return; rotx_ = val; emit(rotxChanged()); if (window()) window()->update(); }
auto setRoty(qreal val) -> void { if (val == roty_) return; roty_ = val; emit(rotyChanged()); if (window()) window()->update(); }
auto setRotz(qreal val) -> void { if (val == rotz_) return; rotz_ = val; emit(rotzChanged()); if (window()) window()->update(); }
signals:
void normalizedRectChanged();
void rotxChanged();
void rotyChanged();
void rotzChanged();
public slots:
void sync();
void cleanup();
private slots:
void handleWindowChanged(QQuickWindow *win);
private:
qreal rotx_{0.0f};
qreal roty_{0.0f};
qreal rotz_{0.0f};
QRectF rect_{qreal(0), qreal(0), qreal(1), qreal(1)};
SquircleRenderer* renderer_ = nullptr;
};
#endif // SQUIRCLE_H
/* vim: set ts=4 sw=4 sts=4 expandtab ffs=unix,dos : */
#include "app/qobjs/squircle.h"
#include <iostream>
#include <random>
#include <QtGui/QOpenGLShaderProgram>
Squircle::Squircle()
{
connect(this, &QQuickItem::windowChanged, this, &Squircle::handleWindowChanged);
}
void Squircle::handleWindowChanged(QQuickWindow* win)
{
if (win) {
connect(win, &QQuickWindow::beforeSynchronizing, this, &Squircle::sync, Qt::DirectConnection);
connect(win, &QQuickWindow::sceneGraphInvalidated, this, &Squircle::cleanup, Qt::DirectConnection);
win->setClearBeforeRendering(false);
}
}
void Squircle::cleanup()
{
if (renderer_) {
delete renderer_;
renderer_ = nullptr;
}
}
SquircleRenderer::SquircleRenderer()
{
format_ = new QSurfaceFormat;
format_->setDepthBufferSize(24);
format_->setStencilBufferSize(8);
format_->setSamples(4);
format_->setMajorVersion(4);
format_->setMinorVersion(3);
format_->setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(*format_);
// pointOpenGLBuffer_.setUsagePattern(QOpenGLBuffer::StreamRead);
pointOpenGLBuffer_.setUsagePattern(QOpenGLBuffer::DynamicRead);
}
SquircleRenderer::~SquircleRenderer()
{
delete renderProgram_;
delete computeProgram_;
delete format_;
}
void Squircle::sync()
{
if (!renderer_) {
renderer_ = new SquircleRenderer();
connect(window(), &QQuickWindow::beforeRendering, renderer_, &SquircleRenderer::paint, Qt::DirectConnection);
}
renderer_->setRotx(rotx_);
renderer_->setRoty(roty_);
renderer_->setRotz(rotz_);
renderer_->setWindow(window());
renderer_->setNormalizedRect(rect_);
}
auto SquircleRenderer::initializeGL() -> void
{
if (!renderProgram_ && !computeProgram_) {
initializeOpenGLFunctions();
computeProgram_ = new QOpenGLShaderProgram();
computeProgram_->addShaderFromSourceFile(QOpenGLShader::Compute, "../app/shaders/pointcloud.comp");
computeProgram_->bindAttributeLocation("Particles", 0);
m_ParticlesLoc = 0;
computeProgram_->link();
if (computeProgram_->bind())
std::cout << "[1] Compute program succesfully bound" << std::endl;
else {
std::cerr << "[1] Compute program could not bind!" << std::endl;
exit(1);
}
m_dxLoc = computeProgram_->uniformLocation("dx");
m_dyLoc = computeProgram_->uniformLocation("dy");
// Setup our vertex buffer object.
pointOpenGLBuffer_.create();
pointOpenGLBuffer_.bind();
pointOpenGLBuffer_.allocate(pointBuffer_.data(), pointBuffer_.vertexCount() * pointBuffer_.stride_);
// local_p = pointOpenGLBuffer_.map(QOpenGLBuffer::ReadWrite);
// if (local_p == NULL) {
// std::cerr << "Could not map buffer to local memory" << std::endl;
// exit(1);
// } else {
// std::cout << "buffer mapped to " << local_p << std::endl;
// }
setupVertexAttribs();
computeProgram_->release();
}
}
auto SquircleRenderer::compute() -> void
{
computeProgram_->bind();
computeProgram_->setUniformValue(m_dxLoc, (GLfloat)5.0);
computeProgram_->setUniformValue(m_dyLoc, (GLfloat)5.0);
pointOpenGLBuffer_.bind();
glDispatchCompute(1024, 1, 1);
// glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
// glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
// This seems to not work when I have the buffer mapped
if (!pointOpenGLBuffer_.read(0, pointBuffer_.data(), pointBuffer_.vertexCount() * pointBuffer_.stride_)) {
std::cerr << "Error! Could not read buffer" << std::endl;
}
pointOpenGLBuffer_.release();
// Used if the buffer if mapped
// pointBuffer_.setData(local_p);
}
void SquircleRenderer::paint()
{
initializeGL();
compute();
}
auto SquircleRenderer::setupVertexAttribs() -> void
{
pointOpenGLBuffer_.bind();
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glEnableVertexAttribArray(m_vertexPositionLoc);
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), 0);
pointOpenGLBuffer_.release();
}
auto SquircleRenderer::setViewport() -> const QSize {
const auto s = window_->size() * window_->devicePixelRatio();
const auto x = s.width() * rect_.x();
const auto y = s.height() * rect_.y();
const auto width = s.width() * (rect_.width() - rect_.x());
const auto height = s.height() * (rect_.height() - rect_.y());
glViewport(x, y, width, height);
return QSize(width, height);
}
auto SquircleRenderer::getViewportMatrix() -> const QMatrix4x4
{
QMatrix4x4 v;
v.viewport(rect_);
return v;
}
/* vim: set ts=4 sw=4 sts=4 expandtab ffs=unix,dos : */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment