Last active
February 24, 2017 16:55
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 : */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 : |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 : |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 : */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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