added mass points

main
Benjamin Kraft 1 year ago
parent 4b53e58724
commit 3c3b1b035b
  1. 15
      shaders/fragment.glsl
  2. 20
      shaders/vertex.glsl
  3. 154
      src/GLWidget.cpp
  4. 10
      src/GLWidget.h
  5. 13
      src/MainWindow.cpp
  6. 21
      src/Pendulum.cpp
  7. 4
      src/Pendulum.h
  8. 3
      src/Simulation.h
  9. 3
      src/main.cpp

@ -4,6 +4,19 @@ out vec4 FragColor;
in vec3 color;
uniform bool drawPoints;
void main() {
FragColor = vec4(color, 1);
if (drawPoints){
vec2 coord = gl_PointCoord - vec2(0.5);
if (length(coord) > 0.5)
discard;
if (length(coord) > 0.4)
FragColor = vec4(1, 1, 1, 1);
else
FragColor = vec4(0, 0, 0, 1);
} else {
FragColor = vec4(color, 1);
}
}

@ -1,13 +1,25 @@
#version 330 core
layout (location = 0) in vec2 vPos;
layout (location = 0) in vec3 vPos;
layout (location = 1) in vec3 vColor;
layout (location = 2) in float vMassRadius;
uniform mat2 VP;
uniform mat3 VP;
uniform bool drawPoints;
uniform float screenSizePixels;
uniform float screenSizeMeters;
uniform float depthOffset;
out vec3 color;
void main() {
gl_Position = vec4(VP * vPos, 0.0, 1.0);
color = vColor;
if (drawPoints){
gl_Position = vec4(VP * vPos, 1.0);
gl_Position.z -= depthOffset * 0.25;
gl_PointSize = vMassRadius / screenSizeMeters * screenSizePixels * 2;
} else {
gl_Position = vec4(VP * vPos, 1.0);
color = vColor;
}
}

@ -28,42 +28,69 @@ void GLWidget::initializeGL() {
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &positionVBO);
glGenBuffers(1, &colorVBO);
glGenBuffers(1, &massRadiiVBO);
glGenBuffers(1, &EBO);
glEnable(GL_POINT_SPRITE);
glEnable(GL_PROGRAM_POINT_SIZE);
glEnable(GL_PRIMITIVE_RESTART);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glClearColor(.15, .15, .15, 1);
std::vector<Pendulum*> empty;
initGPUMemory(&empty);
}
void GLWidget::paintGL() {
auto p = new QPainter(this);
p->setRenderHint(QPainter::Antialiasing);
p->beginNativePainting();
//auto p = new QPainter(this);
//p->setRenderHint(QPainter::Antialiasing);
//p->beginNativePainting();
glEnable(GL_PRIMITIVE_RESTART);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glClearColor(.15, .15, .15, 1);
// Native OpenGL
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, QWidget::width(), QWidget::height());
program->bind();
program->setUniformValue("VP", VP);
program->bind();
program->setUniformValue("VP", VP);
glBindVertexArray(VAO);
glDrawElements(GL_LINE_STRIP, indexCount, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
glBindVertexArray(VAO);
p->endNativePainting();
// Lines
{
program->setUniformValue("drawPoints", false);
glDrawElements(GL_LINE_STRIP, indexCount, GL_UNSIGNED_INT, nullptr);
}
p->setPen(Qt::white);
auto font = p->font();
font.setPixelSize(20);
p->setFont(font);
// Mass Circles
if (showMasses) {
program->setUniformValue("drawPoints", true);
program->setUniformValue("depthOffset", depthOffset);
program->setUniformValue("screenSizePixels", screenSizePixels * 0.9f);
program->setUniformValue("screenSizeMeters", float(simulation->sizeMeters));
glDrawElements(GL_POINTS, indexCount, GL_UNSIGNED_INT, nullptr);
}
fps->newFrame();
QString fpsString = "FPS: " + QString::fromStdString(std::to_string(fps->current));
glBindVertexArray(0);
}
//p->endNativePainting();
/*
// FPS
{
p->setPen(Qt::white);
auto font = p->font();
font.setPixelSize(20);
p->setFont(font);
fps->newFrame();
QString fpsString = "FPS: " + QString::fromStdString(std::to_string(fps->current));
p->drawText(0, 0, 100, 100, Qt::AlignTop | Qt::AlignLeft, fpsString);
}
*/
p->drawText(0, 0, 100, 100, Qt::AlignTop | Qt::AlignLeft, fpsString);
p->end();
//p->end();
}
void GLWidget::timerEvent(QTimerEvent *e) {
@ -81,43 +108,59 @@ bool GLWidget::AnyDialogOpen() {
void GLWidget::initGPUMemory(const std::vector<Pendulum *> *pendula) {
int segmentCount = std::transform_reduce(pendula->begin(), pendula->end(), 0, [](int prev, int curr){
return prev + curr + 1;
}, [](const Pendulum * p){
return p->X.size();
});
std::vector<float> positions;
std::vector<float> colors;
std::vector<float> massRadii;
std::vector<GLuint> indices;
GLuint index = 0;
for (const auto p : *pendula){
if (!pendula->empty()){
// Origin point
positions.push_back(0);
positions.push_back(0);
float depth = 1.f - 1.f / float(segmentCount);
depthOffset = 1.f * 2 / float(segmentCount);
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++);
GLuint index = 0;
for (const auto p : *pendula){
// 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));
// Origin point
positions.push_back(0);
positions.push_back(0);
positions.push_back(depth);
depth -= depthOffset;
colors.resize(colors.size() + 3);
red = &colors.back() - 2;
float * red = &colors.back() - 2;
p->color.getRgbF(red, red + 1, red + 2);
massRadii.push_back(float(p->M[segment]));
massRadii.push_back(0);
indices.push_back(index++);
}
// Primitive Restart
indices.push_back(0xFFFFFFFF);
// 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));
positions.push_back(depth);
depth -= depthOffset;
colors.resize(colors.size() + 3);
red = &colors.back() - 2;
p->color.getRgbF(red, red + 1, red + 2);
massRadii.push_back(float(sqrt(p->M[segment]) / 5));
indices.push_back(index++);
}
// Primitive Restart
indices.push_back(0xFFFFFFFF);
}
}
indexCount = GLsizei(indices.size());
@ -127,7 +170,7 @@ void GLWidget::initGPUMemory(const std::vector<Pendulum *> *pendula) {
glBindBuffer(GL_ARRAY_BUFFER, positionVBO);
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);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
@ -135,6 +178,11 @@ void GLWidget::initGPUMemory(const std::vector<Pendulum *> *pendula) {
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, massRadiiVBO);
glBufferData(GL_ARRAY_BUFFER, GLsizeiptr(massRadii.size() * sizeof(float)), massRadii.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 1 * sizeof(float), nullptr);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GLsizeiptr(indices.size() * sizeof(GLuint)), indices.data(), GL_STATIC_DRAW);
@ -152,10 +200,11 @@ void GLWidget::changePosition(const std::vector<Pendulum *> *pendula) {
if (positions){
size_t index = 0;
for (const auto p : *pendula){
index += 2;
index += 3;
for (auto x : p->X){
positions[index++] = float(x.x);
positions[index++] = float(x.y);
index++;
}
}
}
@ -165,13 +214,20 @@ void GLWidget::changePosition(const std::vector<Pendulum *> *pendula) {
}
void GLWidget::resizeGL(int w, int h) {
float m = std::min(float(w), float(h));
float scale = 1 / (float(simulation->size) / 2) * 0.9f;
screenSizePixels = std::min(float(w), float(h));
float scale = screenSizePixels / float(simulation->sizeMeters) * 2 * 0.9f;
VP.setToIdentity();
VP(0, 0) = 1 / float(w);
VP(1, 1) = -1 / float(h);
VP *= m * scale;
VP *= scale;
VP(2, 2) = 1;
glViewport(0, 0, w, h);
}
void GLWidget::showMassesChanged(int state) {
showMasses = state == Qt::Checked;
}

@ -2,7 +2,7 @@
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QMatrix2x2>
#include <QMatrix3x3>
class Pendulum;
class Simulation;
@ -17,6 +17,8 @@ protected:
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
public slots:
void showMassesChanged(int state);
private slots:
void initGPUMemory(const std::vector<Pendulum *> *pendula);
void changePosition(const std::vector<Pendulum *> *pendula);
@ -25,10 +27,14 @@ private:
GLuint VAO;
GLuint positionVBO;
GLuint colorVBO;
GLuint massRadiiVBO;
GLuint EBO;
GLsizei indexCount = 0;
GLsizei positionCount = 0;
QMatrix2x2 VP;
QMatrix3x3 VP;
float screenSizePixels;
float depthOffset;
bool showMasses;
Simulation * simulation;
FPS * fps;

@ -347,7 +347,7 @@ QWidget * MainWindow::buildSimulationUI() {
auto reset = new Button("Reset", ":/icons/refresh.svg");
auto togglePlay = new Button("Resume", ":/icons/play.svg");
reset->setToolTip("Reset Simulation controls");
reset->setToolTip("Reset Simulation Controls");
togglePlay->setToolTip("Pause/Resume Simulation");
togglePlay->setStyleSheet("background-color: #aaaaff");
@ -362,6 +362,15 @@ QWidget * MainWindow::buildSimulationUI() {
btnLyt->addWidget(reset);
btnLyt->addWidget(togglePlay);
// Show Masses
{
auto showMasses = new QCheckBox("Show Masses");
connect(showMasses, &QCheckBox::stateChanged, glWidget, &GLWidget::showMassesChanged);
showMasses->setChecked(true);
lyt->addWidget(showMasses);
}
return w;
}
@ -383,7 +392,7 @@ void MainWindow::resetLengths() {
void MainWindow::normalizeLengths() {
double sum = std::reduce(lengths.begin(), lengths.begin() + segments);
double factor = simulation->size / 2 / sum;
double factor = simulation->sizeMeters / 2 / sum;
for (int i = 0; i < segments; i++){
lengths[i] *= factor;
}

@ -19,29 +19,10 @@ Pendulum::Pendulum(const std::vector<double> &M,
}
}
void Pendulum::draw(QPainter *p, double scale) const {
p->setPen(color);
p->setBrush(Qt::NoBrush);
QPainterPath path;
path.moveTo(0, 0);
for (auto x : X){
x = x * scale;
path.lineTo(x.x, x.y);
}
p->drawPath(path);
p->setPen(Qt::NoPen);
p->setBrush(Qt::white);
for (int i = 0; i < M.size(); i++){
double r = sqrt(M[i]) * scale / 30;
p->drawEllipse(QPointF(X[i].x, X[i].y) * scale, r * 2, r * 2);
}
}
void Pendulum::update(double h, double g) {
// Classic PBD needs multiple loops
// Here, I can put all operations safely into one single loop,
// Here, I can safely put all operations into one single loop,
// because the positions and velocities in X, V are sorted
// from the pendulum's origin to it's end which means
// that only direct neighbours affect each other

@ -6,15 +6,11 @@
#include "Vector.h"
#include "GLWidget.h"
class QPainter;
class Pendulum {
public:
explicit Pendulum(const std::vector<double> &M,
const std::vector<double> &L,
QColor color, double startAngle);
void draw(QPainter*, double) const;
void update(double, double);
private:
friend class GLWidget;

@ -7,7 +7,6 @@
using namespace std::chrono;
class QPainter;
class QTimer;
class Simulation : public QObject {
@ -15,7 +14,7 @@ class Simulation : public QObject {
public:
explicit Simulation();
double size = 50;
double sizeMeters = 50;
double gravity {};
double timescale {};

@ -12,6 +12,9 @@ int main(int argc, char* argv[]) {
QSurfaceFormat fmt;
fmt.setSamples(4);
fmt.setDepthBufferSize(24);
//fmt.setVersion(3, 3);
//fmt.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(fmt);
MainWindow w;

Loading…
Cancel
Save