drawing done with opengl, without mass points

main
Benjamin Kraft 1 year ago
parent 81f5f3fe7b
commit 49dc19b39f
  1. 4
      shaders/vertex.glsl
  2. 148
      src/GLWidget.cpp
  3. 14
      src/GLWidget.h
  4. 4
      src/MainWindow.cpp
  5. 2
      src/Pendulum.h
  6. 36
      src/Simulation.cpp
  7. 6
      src/Simulation.h

@ -3,9 +3,11 @@
layout (location = 0) in vec2 vPos;
layout (location = 1) in vec3 vColor;
uniform mat2 VP;
out vec3 color;
void main() {
gl_Position = vec4(vPos, 0.0, 1.0);
gl_Position = vec4(VP * vPos, 0.0, 1.0);
color = vColor;
}

@ -13,60 +13,22 @@ GLWidget::GLWidget(Simulation * simulation) : simulation(simulation) {
startTimer(1000 / 144);
fps = new FPS;
fps->setUpdateInterval(500);
connect(simulation, &Simulation::pendulaChanged, this, &GLWidget::initGPUMemory);
connect(simulation, &Simulation::layoutChanged, this, &GLWidget::initGPUMemory);
connect(simulation, &Simulation::positionChanged, this, &GLWidget::changePosition);
}
void GLWidget::initializeGL() {
initializeOpenGLFunctions();
glEnable(GL_PRIMITIVE_RESTART);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glClearColor(.15, .15, .15, 1);
program = new QOpenGLShaderProgram;
program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vertex.glsl");
program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fragment.glsl");
program->link();
program->bind();
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
float vertices[] = {
-0.5, -0.5,
0.5, -0.5,
0.5, 0.5,
-0.5, 0.5
};
float colors[] = {
1, 0, 0,
0, 1, 0,
0, 0, 1,
1, 1, 0
};
GLushort indices[] = {
0, 1, 0xffff, 2, 3
};
glGenBuffers(1, &positionVBO);
glBindBuffer(GL_ARRAY_BUFFER, positionVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
GLuint colorVBO;
glGenBuffers(1, &colorVBO);
glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glEnableVertexAttribArray(1);
GLuint ebo;
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindVertexArray(0);
glGenBuffers(1, &EBO);
}
void GLWidget::paintGL() {
@ -74,13 +36,17 @@ void GLWidget::paintGL() {
p->setRenderHint(QPainter::Antialiasing);
p->beginNativePainting();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_PRIMITIVE_RESTART);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glClearColor(.15, .15, .15, 1);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, QWidget::width(), QWidget::height());
program->bind();
program->setUniformValue("VP", VP);
glBindVertexArray(VAO);
glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, nullptr);
simulation->draw(nullptr, std::min(width(), height()));
glDrawElements(GL_LINE_STRIP, indexCount, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
p->endNativePainting();
@ -110,12 +76,100 @@ bool GLWidget::AnyDialogOpen() {
return false;
}
void GLWidget::initGPUMemory(const std::vector<Pendulum *> &addPendula) {
void GLWidget::initGPUMemory(const std::vector<Pendulum *> *pendula) {
std::vector<float> positions;
std::vector<float> colors;
std::vector<float> massRadii;
std::vector<GLuint> indices;
GLuint index = 0;
for (const auto p : *pendula){
// Origin point
positions.push_back(0);
positions.push_back(0);
colors.resize(colors.size() + 3);
float * red = &colors.back() - 2;
p->color.getRgbF(red, red + 1, red + 2);
massRadii.push_back(0);
indices.push_back(index++);
// All other points
for (int segment = 0; segment < p->M.size(); segment++){
Vector pos = p->X[segment];
positions.push_back(float(pos.x));
positions.push_back(float(pos.y));
colors.resize(colors.size() + 3);
red = &colors.back() - 2;
p->color.getRgbF(red, red + 1, red + 2);
massRadii.push_back(float(p->M[segment]));
indices.push_back(index++);
}
// Primitive Restart
indices.push_back(0xFFFFFFFF);
}
indexCount = GLsizei(indices.size());
positionCount = GLsizei(positions.size());
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, positionVBO);
auto positions = (GLfloat*) glMapBufferRange(GL_ARRAY_BUFFER, 0, 2 * 3 * sizeof(float), GL_MAP_WRITE_BIT);
glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(positions.size() * sizeof(float)), positions.data(), GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(colors.size() * sizeof(float)), colors.data(), GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GLsizeiptr(indices.size() * sizeof(GLuint)), indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
simulation->pendulaMutex.unlock();
}
void GLWidget::changePosition(const std::vector<Pendulum *> *pendula) {
glBindBuffer(GL_ARRAY_BUFFER, positionVBO);
auto positions = (GLfloat*) glMapBufferRange(GL_ARRAY_BUFFER, 0, GLsizeiptr(positionCount * sizeof(float)), GL_MAP_WRITE_BIT);
if (positions){
size_t index = 0;
for (const auto p : *pendula){
index += 2;
for (auto x : p->X){
positions[index++] = float(x.x);
positions[index++] = float(x.y);
}
}
}
simulation->pendulaMutex.unlock();
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void GLWidget::resizeGL(int w, int h) {
float m = std::min(float(w), float(h));
float scale = 1 / (float(simulation->size) / 2) * 0.9f;
VP.setToIdentity();
VP(0, 0) = 1 / float(w);
VP(1, 1) = -1 / float(h);
VP *= m * scale;
}

@ -1,5 +1,8 @@
#pragma once
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QMatrix2x2>
class Pendulum;
class Simulation;
@ -13,13 +16,20 @@ protected:
void timerEvent(QTimerEvent* e) override;
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
private slots:
void initGPUMemory(const std::vector<Pendulum *> &addPendula);
void initGPUMemory(const std::vector<Pendulum *> *pendula);
void changePosition(const std::vector<Pendulum *> *pendula);
private:
QOpenGLShaderProgram * program;
GLuint VAO;
GLuint positionVBO;
GLsizei indexCount;
GLuint colorVBO;
GLuint EBO;
GLsizei indexCount = 0;
GLsizei positionCount = 0;
QMatrix2x2 VP;
Simulation * simulation;
FPS * fps;
static bool AnyDialogOpen();

@ -333,7 +333,7 @@ QWidget * MainWindow::buildSimulationUI() {
timescaleSlider->setMinimum(1);
timescaleSlider->setMaximum(500);
substepsSlider->setMinimum(1);
substepsSlider->setMaximum(1000);
substepsSlider->setMaximum(100);
resetSimulationControl();
@ -433,7 +433,7 @@ void MainWindow::add() {
void MainWindow::resetSimulationControl() {
gravitySlider->setValue(981);
timescaleSlider->setValue(100);
substepsSlider->setValue(30);
substepsSlider->setValue(5);
}
void MainWindow::toggleSimulation() {

@ -4,6 +4,7 @@
#include <QVector2D>
#include <QColor>
#include "Vector.h"
#include "GLWidget.h"
class QPainter;
@ -16,6 +17,7 @@ public:
void draw(QPainter*, double) const;
void update(double, double);
private:
friend class GLWidget;
std::vector<Vector> X, V;
std::vector<double> M, L;
QColor color;

@ -13,24 +13,10 @@ Simulation::Simulation() {
lastUpdate = system_clock::now();
};
void Simulation::draw(QPainter *p, int screenSize) {
pendulaMutex.lock();
double scale = screenSize * 0.95 / size;
/*
for (const auto pendulum : pendula)
pendulum->draw(p, scale);
*/
pendulaMutex.unlock();
}
void Simulation::update() {
auto thisUpdate = system_clock::now();
auto ms = (int)duration_cast<milliseconds>(thisUpdate - lastUpdate).count();
std::cout << ms << std::endl;
lastUpdate = thisUpdate;
if (!isPlaying)
@ -40,23 +26,29 @@ void Simulation::update() {
h /= substeps;
pendulaMutex.lock();
#pragma omp parallel for
for (int i = 0; i < pendula.size(); i++) // NOLINT(*-loop-convert) // no ranged based for msvc
for (int i = 0; i < pendula.size(); i++){ // NOLINT(*-loop-convert) // not ranged based for msvc
for (int k = 0; k < substeps; k++)
pendula[i]->update(h, gravity);
}
emit positionChanged(&pendula);
}
void Simulation::clearPendula() {
pendulaMutex.lock();
for (auto p : pendula)
for (Pendulum* &p : pendula){
delete p;
p = nullptr;
}
pendula.clear();
pendula.shrink_to_fit();
pendulaMutex.unlock();
emit pendulaChanged(pendula);
emit layoutChanged(&pendula);
}
void Simulation::addPendula(const std::vector<Pendulum *> &add) {
@ -65,8 +57,6 @@ void Simulation::addPendula(const std::vector<Pendulum *> &add) {
for (auto p : add)
pendula.push_back(p);
pendulaMutex.unlock();
emit pendulaChanged(pendula);
emit layoutChanged(&pendula);
}

@ -23,16 +23,16 @@ public:
bool isPlaying = false;
void draw(QPainter*, int);
std::mutex pendulaMutex;
signals:
void pendulaChanged(const std::vector<Pendulum *> &newPendula);
void layoutChanged(const std::vector<Pendulum *> *newPendula);
void positionChanged(const std::vector<Pendulum *> *changedPendula);
public slots:
void clearPendula();
void addPendula(const std::vector<Pendulum *> &add);
private slots:
void update();
private:
std::mutex pendulaMutex;
QTimer * timer;
int updateInterval = 17;
std::vector<Pendulum *> pendula;

Loading…
Cancel
Save