commit 3bbdcc60621da9e26cc6e02656ff71fada69e6c2 Author: papush! Date: Wed Oct 6 19:49:42 2021 +0200 initial commit diff --git a/fish.cpp b/fish.cpp new file mode 100644 index 0000000..8ba8037 --- /dev/null +++ b/fish.cpp @@ -0,0 +1,11 @@ +#include "fish.h" + + +void Fish::animate(float dt) { + position += velocity * dt; +} + + +bool Fish::isCloseTo(const QVector3D &point) { + return position.distanceToPoint(point) < range; +} diff --git a/fish.h b/fish.h new file mode 100644 index 0000000..fe77210 --- /dev/null +++ b/fish.h @@ -0,0 +1,20 @@ +#ifndef FISH_H +#define FISH_H + +#include +#include + + +struct Fish { + QVector3D position; + QVector3D velocity; + float size; + float range; + + void animate(float dt); + bool isCloseTo(const QVector3D &point); + void display(QOpenGLExtraFunctions *glf); +}; + + +#endif \ No newline at end of file diff --git a/fish_painter.cpp b/fish_painter.cpp new file mode 100644 index 0000000..9259452 --- /dev/null +++ b/fish_painter.cpp @@ -0,0 +1,65 @@ +#include "fish_painter.h" + +#include + + +const GLfloat vertices[] = { + 1, 0, 0, + -1, .5, 0, + -1, -.5, 0, +}; + + +void FishPainter::create(QOpenGLExtraFunctions *glf) { + (void) glf; + + if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, + ":/shaders/fish.vert")) { + qCritical() << program.log(); + } + if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, + ":/shaders/fish.frag")) { + qCritical() << program.log(); + } + if (!program.link()) { + qCritical() << program.log(); + } + + vao.create(); + + {QOpenGLVertexArrayObject::Binder bind(&vao); + vbo.create(); + vbo.bind(); + vbo.allocate(vertices, 9 * sizeof (GLfloat)); + program.bind(); + program.setAttributeBuffer("position", GL_FLOAT, 0, 3); + program.enableAttributeArray("position"); + } +} + + +void FishPainter::paint(QOpenGLExtraFunctions *glf, + const QMatrix4x4 &projection, + const QMatrix4x4 &view, + const std::vector fishes) { + const QVector3D X(1, 0, 0); + {QOpenGLVertexArrayObject::Binder bind(&vao); + program.setUniformValue("projection", projection); + program.setUniformValue("view", view); + QMatrix4x4 model; + for (const Fish &fish : fishes) { + model.setToIdentity(); + model.translate(fish.position); + if (!fish.velocity.isNull()) { + double dot = QVector3D::dotProduct(X, fish.velocity); + double angle = qAcos(dot / fish.velocity.length()); + if (angle != 0) { + model.rotate(qRadiansToDegrees(angle), + QVector3D::crossProduct(X, fish.velocity)); + } + } + program.setUniformValue("model", model); + glf->glDrawArrays(GL_TRIANGLES, 0, 3); + } + } +} diff --git a/fish_painter.h b/fish_painter.h new file mode 100644 index 0000000..d1041be --- /dev/null +++ b/fish_painter.h @@ -0,0 +1,27 @@ +#ifndef FISH_VIEWER_H +#define FISH_VIEWER_H + +#include "fish.h" + +#include +#include +#include +#include +#include + + +class FishPainter { + QOpenGLVertexArrayObject vao; + QOpenGLBuffer vbo; + QOpenGLShaderProgram program; + + public: + void create(QOpenGLExtraFunctions *glf); + void paint(QOpenGLExtraFunctions *glf, + const QMatrix4x4 &projection, + const QMatrix4x4 &view, + const std::vector fishes); +}; + + +#endif \ No newline at end of file diff --git a/fish_schooling.cpp b/fish_schooling.cpp new file mode 100644 index 0000000..7e844fa --- /dev/null +++ b/fish_schooling.cpp @@ -0,0 +1,61 @@ +#include "fish_schooling.h" + +#include + + +static double generateDoubleBetween(QRandomGenerator *rng, + double min, double max) { + return rng->generateDouble() * (max - min) + min; +} + + +FishSchooling::FishSchooling(size_t count, QVector3D bounds) + :bounds(bounds) { + QRandomGenerator *rng = QRandomGenerator::global(); + for (size_t i = 0; i < count; i++) { + QVector3D position( + generateDoubleBetween(rng, -bounds.x()/2, bounds.x()/2), + generateDoubleBetween(rng, -bounds.y()/2, bounds.y()/2), + generateDoubleBetween(rng, -bounds.z()/2, bounds.z()/2)); + QVector3D velocity( + generateDoubleBetween(rng, -5, 5), + generateDoubleBetween(rng, -5, 5), + generateDoubleBetween(rng, -5, 5)); + float size = 10; + fishes.push_back({position, velocity, size, size * 10}); + } +} + + +void FishSchooling::animate(float dt) { + for (Fish &fish : fishes) { + size_t n_neighbors = 0; + QVector3D distance; + QVector3D cog; + QVector3D velocity; + for (Fish &fish2 : fishes) { + if (&fish2 != &fish && fish.isCloseTo(fish2.position)) { + distance += fish2.position - fish.position; + cog += fish2.position; + velocity += fish2.velocity; + n_neighbors++; + } + } + if (n_neighbors != 0) { + distance /= n_neighbors; + cog /= n_neighbors; + velocity /= n_neighbors; + QVector3D separation = -distance; + QVector3D alignment = fish.velocity - velocity; + QVector3D cohesion = cog - fish.position; + QVector3D velocity_tgt = .8 * separation + 1.5 * alignment + cohesion; + const float L = .1; + fish.velocity = L * velocity_tgt + (1 - L) * fish.velocity; + } + float speed = fish.velocity.length(); + if (speed > 10) { + fish.velocity = fish.velocity / speed * 10; + } + fish.position += fish.velocity * dt; + } +} diff --git a/fish_schooling.h b/fish_schooling.h new file mode 100644 index 0000000..f33b0fa --- /dev/null +++ b/fish_schooling.h @@ -0,0 +1,18 @@ +#ifndef FISH_SCHOOLING_H +#define FISH_SCHOOLING_H + +#include "fish.h" + + +class FishSchooling { + QVector3D bounds; + + public: + std::vector fishes; + + FishSchooling(size_t count=10, QVector3D bounds={20, 20, 20}); + void animate(float dt); +}; + + +#endif \ No newline at end of file diff --git a/glarea.cpp b/glarea.cpp new file mode 100644 index 0000000..9f5684f --- /dev/null +++ b/glarea.cpp @@ -0,0 +1,145 @@ +// Basé sur : +// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019 + +#include "glarea.h" +#include +#include +#include + + + +GLArea::GLArea(QWidget *parent) : + QOpenGLWidget(parent) +{ + QSurfaceFormat sf; + sf.setDepthBufferSize(24); + sf.setSamples(16); + setFormat(sf); + + setEnabled(true); // événements clavier et souris + setFocusPolicy(Qt::StrongFocus); // accepte focus + setFocus(); // donne le focus +} + + +GLArea::~GLArea() +{ + makeCurrent(); + doneCurrent(); +} + + +void GLArea::initializeGL() +{ + initializeOpenGLFunctions(); + glClearColor(0.5f,0.5f,1.0f,1.0f); + glEnable(GL_DEPTH_TEST); + emit onInit((QOpenGLExtraFunctions *) this); +} + + +void GLArea::resizeGL(int w, int h) +{ + glViewport(0, 0, w, h); + windowRatio = float(w) / h; +} + + +void GLArea::paintGL() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Matrice de projection + QMatrix4x4 projectionMatrix; + projectionMatrix.perspective(45.0f, windowRatio, 1.0f, 1000.0f); + + // Matrice de vue (caméra) + QMatrix4x4 viewMatrix; + viewMatrix.translate(xPos, yPos, zPos); + viewMatrix.rotate(xRot, 1, 0, 0); + viewMatrix.rotate(yRot, 0, 1, 0); + viewMatrix.rotate(zRot, 0, 0, 1); + + emit onPaint((QOpenGLExtraFunctions *) this, + projectionMatrix, + viewMatrix); +} + + +void GLArea::keyPressEvent(QKeyEvent *ev) +{ + float da = 1.0f; + + switch(ev->key()) { + case Qt::Key_A : + xRot -= da; + update(); + break; + + case Qt::Key_Q : + xRot += da; + update(); + break; + + case Qt::Key_Z : + yRot -= da; + update(); + break; + + case Qt::Key_S : + yRot += da; + update(); + break; + + case Qt::Key_E : + zRot -= da; + update(); + break; + + case Qt::Key_D : + zRot += da; + update(); + break; + } +} + + +void GLArea::keyReleaseEvent(QKeyEvent *ev) +{ + qDebug() << __FUNCTION__ << ev->text(); +} + + +void GLArea::mousePressEvent(QMouseEvent *ev) +{ + lastPos = ev->pos(); +} + + +void GLArea::mouseReleaseEvent(QMouseEvent *ev) +{ + qDebug() << __FUNCTION__ << ev->x() << ev->y() << ev->button(); +} + + +void GLArea::mouseMoveEvent(QMouseEvent *ev) +{ + int dx = ev->x() - lastPos.x(); + int dy = ev->y() - lastPos.y(); + + if (ev->buttons() & Qt::LeftButton) { + xRot += dy; + yRot += dx; + update(); + } else if (ev->buttons() & Qt::RightButton) { + xPos += dx/10.0f; + yPos -= dy/10.0f; + update(); + } else if (ev->buttons() & Qt::MidButton) { + xPos += dx/10.0f; + zPos += dy; + update(); + } + + lastPos = ev->pos(); +} diff --git a/glarea.h b/glarea.h new file mode 100644 index 0000000..6913408 --- /dev/null +++ b/glarea.h @@ -0,0 +1,50 @@ +// Basé sur : +// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019 + +#ifndef GLAREA_H +#define GLAREA_H + +#include +#include +#include +#include +#include +#include +#include + + +class GLArea : public QOpenGLWidget, + protected QOpenGLExtraFunctions +{ + Q_OBJECT + +public: + explicit GLArea(QWidget *parent = nullptr); + ~GLArea() override; + +signals: + void onInit(QOpenGLExtraFunctions *glf); + void onPaint(QOpenGLExtraFunctions *glf, + const QMatrix4x4 &projection, + const QMatrix4x4 &view); + +protected: + void initializeGL() override; + void doProjection(); + void resizeGL(int w, int h) override; + void paintGL() override; + void keyPressEvent(QKeyEvent *ev) override; + void keyReleaseEvent(QKeyEvent *ev) override; + void mousePressEvent(QMouseEvent *ev) override; + void mouseReleaseEvent(QMouseEvent *ev) override; + void mouseMoveEvent(QMouseEvent *ev) override; + +private: + float xRot=20.0f, yRot=0.0f, zRot=0.0f; + float xPos=0.0f, yPos=0.0f, zPos=-50.0f; + float dt = 0; + float windowRatio = 1.0f; + QPoint lastPos; +}; + +#endif // GLAREA_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..f031955 --- /dev/null +++ b/main.cpp @@ -0,0 +1,51 @@ +// Basé sur : +// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019 + +#include "princ.h" +#include "glarea.h" +#include "fish_painter.h" +#include "fish_schooling.h" +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + Princ main_window; + + FishSchooling schooling(20); + FishPainter fish_painter; + + GLArea *glarea = main_window.glarea; + QObject::connect(glarea, &GLArea::onInit, + [&](QOpenGLExtraFunctions *glf) { + fish_painter.create(glf); + }); + QObject::connect(glarea, &GLArea::onPaint, + [&](QOpenGLExtraFunctions *glf, + const QMatrix4x4 &projection, + const QMatrix4x4 &view) { + fish_painter.paint(glf, projection, view, + schooling.fishes); + }); + + QTimer timer; + timer.setInterval(1000. / 60); + QElapsedTimer elapsed_timer; + elapsed_timer.start(); + qint64 old_chrono = 0; + QObject::connect(&timer, &QTimer::timeout, [&]() { + qint64 chrono = elapsed_timer.elapsed(); + float dt = (chrono - old_chrono) / 1000.0f; + old_chrono = chrono; + schooling.animate(dt); + glarea->update(); + }); + timer.start(); + + + main_window.show(); + return app.exec(); +} diff --git a/princ.cpp b/princ.cpp new file mode 100644 index 0000000..39ec84a --- /dev/null +++ b/princ.cpp @@ -0,0 +1,11 @@ +// Basé sur : +// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019 + +#include "princ.h" +#include +#include + +Princ::Princ(QWidget *parent) : QMainWindow(parent) +{ + setupUi(this); +} diff --git a/princ.h b/princ.h new file mode 100644 index 0000000..f0a4b32 --- /dev/null +++ b/princ.h @@ -0,0 +1,17 @@ +// Basé sur : +// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019 + +#ifndef PRINC_H +#define PRINC_H + +#include "ui_princ.h" + +class Princ : public QMainWindow, public Ui::Princ +{ + Q_OBJECT + +public: + explicit Princ(QWidget *parent = nullptr); +}; + +#endif // PRINC_H diff --git a/princ.ui b/princ.ui new file mode 100644 index 0000000..d16f832 --- /dev/null +++ b/princ.ui @@ -0,0 +1,65 @@ + + + Princ + + + + 0 + 0 + 765 + 600 + + + + TP1 + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + 765 + 20 + + + + + + + + GLArea + QOpenGLWidget +
glarea.h
+ + onSmokeIntervalChanged(double) + onSmokeMinTTLChanged(double) + onSmokeMaxTTLChanged(double) + onSmokeColorChanged(QColor) + +
+
+ + +
diff --git a/shaders/fish.frag b/shaders/fish.frag new file mode 100644 index 0000000..84c86d5 --- /dev/null +++ b/shaders/fish.frag @@ -0,0 +1,3 @@ +void main() { + gl_FragColor = vec4(1, 0, .3, 1); +} diff --git a/shaders/fish.vert b/shaders/fish.vert new file mode 100644 index 0000000..9aa05ca --- /dev/null +++ b/shaders/fish.vert @@ -0,0 +1,9 @@ +attribute vec3 position; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 model; + +void main() { + gl_Position = projection * view * model * vec4(position, 1); +} diff --git a/tp02.pro b/tp02.pro new file mode 100644 index 0000000..f1dddeb --- /dev/null +++ b/tp02.pro @@ -0,0 +1,23 @@ +QT += core gui +CONFIG += c++14 +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = tp02 +TEMPLATE = app + +SOURCES += main.cpp +SOURCES += princ.cpp +SOURCES += glarea.cpp +SOURCES += fish.cpp +SOURCES += fish_painter.cpp +SOURCES += fish_schooling.cpp + +HEADERS += princ.h +HEADERS += glarea.h +HEADERS += fish.h +HEADERS += fish_painter.h +HEADERS += fish_schooling.h + +FORMS += princ.ui + +RESOURCES += tp02.qrc diff --git a/tp02.qrc b/tp02.qrc new file mode 100644 index 0000000..1511cd8 --- /dev/null +++ b/tp02.qrc @@ -0,0 +1,7 @@ + + + + shaders/fish.vert + shaders/fish.frag + +