initial commit
This commit is contained in:
commit
3bbdcc6062
11
fish.cpp
Normal file
11
fish.cpp
Normal 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
20
fish.h
Normal 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
65
fish_painter.cpp
Normal 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
27
fish_painter.h
Normal 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
61
fish_schooling.cpp
Normal 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
18
fish_schooling.h
Normal 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
145
glarea.cpp
Normal 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
50
glarea.h
Normal 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
51
main.cpp
Normal 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
11
princ.cpp
Normal 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
17
princ.h
Normal 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
65
princ.ui
Normal 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
3
shaders/fish.frag
Normal file
@ -0,0 +1,3 @@
|
||||
void main() {
|
||||
gl_FragColor = vec4(1, 0, .3, 1);
|
||||
}
|
9
shaders/fish.vert
Normal file
9
shaders/fish.vert
Normal 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
23
tp02.pro
Normal 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
|
Loading…
Reference in New Issue
Block a user