initial commit

This commit is contained in:
papush! 2021-10-06 19:49:42 +02:00
commit 3bbdcc6062
16 changed files with 583 additions and 0 deletions

11
fish.cpp Normal file
View File

@ -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;
}

20
fish.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef FISH_H
#define FISH_H
#include <QVector3D>
#include <QOpenGLExtraFunctions>
struct Fish {
QVector3D position;
QVector3D velocity;
float size;
float range;
void animate(float dt);
bool isCloseTo(const QVector3D &point);
void display(QOpenGLExtraFunctions *glf);
};
#endif

65
fish_painter.cpp Normal file
View File

@ -0,0 +1,65 @@
#include "fish_painter.h"
#include <QtMath>
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<Fish> 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);
}
}
}

27
fish_painter.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef FISH_VIEWER_H
#define FISH_VIEWER_H
#include "fish.h"
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLExtraFunctions>
#include <QMatrix4x4>
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<Fish> fishes);
};
#endif

61
fish_schooling.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "fish_schooling.h"
#include <QRandomGenerator>
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;
}
}

18
fish_schooling.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef FISH_SCHOOLING_H
#define FISH_SCHOOLING_H
#include "fish.h"
class FishSchooling {
QVector3D bounds;
public:
std::vector<Fish> fishes;
FishSchooling(size_t count=10, QVector3D bounds={20, 20, 20});
void animate(float dt);
};
#endif

145
glarea.cpp Normal file
View File

@ -0,0 +1,145 @@
// Basé sur :
// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019
#include "glarea.h"
#include <QDebug>
#include <QSurfaceFormat>
#include <QMatrix4x4>
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();
}

50
glarea.h Normal file
View File

@ -0,0 +1,50 @@
// Basé sur :
// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019
#ifndef GLAREA_H
#define GLAREA_H
#include <QKeyEvent>
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QColor>
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

51
main.cpp Normal file
View File

@ -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 <QApplication>
#include <QTimer>
#include <QElapsedTimer>
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();
}

11
princ.cpp Normal file
View File

@ -0,0 +1,11 @@
// Basé sur :
// CC-BY Edouard.Thiel@univ-amu.fr - 22/01/2019
#include "princ.h"
#include <QDebug>
#include <QColorDialog>
Princ::Princ(QWidget *parent) : QMainWindow(parent)
{
setupUi(this);
}

17
princ.h Normal file
View File

@ -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

65
princ.ui Normal file
View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Princ</class>
<widget class="QMainWindow" name="Princ">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>765</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>TP1</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout"/>
</item>
<item>
<widget class="GLArea" name="glarea">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>765</width>
<height>20</height>
</rect>
</property>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>GLArea</class>
<extends>QOpenGLWidget</extends>
<header>glarea.h</header>
<slots>
<slot>onSmokeIntervalChanged(double)</slot>
<slot>onSmokeMinTTLChanged(double)</slot>
<slot>onSmokeMaxTTLChanged(double)</slot>
<slot>onSmokeColorChanged(QColor)</slot>
</slots>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

3
shaders/fish.frag Normal file
View File

@ -0,0 +1,3 @@
void main() {
gl_FragColor = vec4(1, 0, .3, 1);
}

9
shaders/fish.vert Normal file
View File

@ -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);
}

23
tp02.pro Normal file
View File

@ -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

7
tp02.qrc Normal file
View File

@ -0,0 +1,7 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file>shaders/fish.vert</file>
<file>shaders/fish.frag</file>
</qresource>
</RCC>