From 6c39ee710a25879e22997107fef1612ccf3a1055 Mon Sep 17 00:00:00 2001 From: ao Date: Tue, 9 Oct 2018 23:29:30 +0200 Subject: [PATCH] Flawless BSpline 1D --- src/bspline.cpp | 260 +++++++++++++++++++++++-------- src/bspline.h | 51 ++++-- src/hello_spline/hellospline.cpp | 20 ++- src/mainwindow.cpp | 4 +- src/mainwindow.h | 2 +- src/mainwindow.ui | 2 +- src/scene.cpp | 1 + src/scene.h | 2 +- 8 files changed, 262 insertions(+), 80 deletions(-) diff --git a/src/bspline.cpp b/src/bspline.cpp index 061b037..9fc89bf 100644 --- a/src/bspline.cpp +++ b/src/bspline.cpp @@ -1,97 +1,231 @@ #include "bspline.h" +#include -BSpline::BSpline(int k, double step, int np1) +BSpline::BSpline( + ESpline typeSpline, + int k, + EPolygone typePolygone, + EVecteurNodal typeVecteur, + int nbPtsCtrlX, + int nbPtsCtrlZ, + float stepX, + float stepY) { - // Initialisation des valeurs - // Ordre k = 2 - _k = k; - _step = step; - _np1 = np1; - // Vecteur Nodal Uniforme de np1 valeurs - for(int i = 0; i < k+np1; ++i) - _vecteurNodal.push_back(i); - // Points de contrôle - _pointsDeControle.push_back(glm::vec3(-2, 0, -5)); - _pointsDeControle.push_back(glm::vec3(-1, 0, -5)); - _pointsDeControle.push_back(glm::vec3(-1, 1, -5)); - _pointsDeControle.push_back(glm::vec3( 1, 1, -5)); - _pointsDeControle.push_back(glm::vec3( 1, 0, -5)); - _pointsDeControle.push_back(glm::vec3( 2, 0, -5)); + // Simple vérification + switch (typeSpline) { + case ESpline::SPLINE1D: + assert(k <= nbPtsCtrlX); + break; + case ESpline::SPLINE2D: + assert(k <= nbPtsCtrlX && k <= nbPtsCtrlZ); + break; + } + + // Initialisation des valeurs + _k = k; + _stepX = stepX; + _stepY = stepY; + srand(time(NULL)); + + // Génération du polygone de contrôle + construirePolygone(typePolygone, nbPtsCtrlX, nbPtsCtrlZ); + + // Calcul du vecteur nodal de nbPtsCtrl valeurs + construireVecteurNodal(typeVecteur); + switch (typeSpline) { + case ESpline::SPLINE1D: + calculerSpline1D(); + break; + case ESpline::SPLINE2D: + calculerSpline2D(); + break; + default: + std::cerr << "Type de spline inconnu" << std::endl; + break; + } - computeSpline(); } -void BSpline::computeSpline() +void BSpline::calculerSpline1D() { // Init - int dec = 0, i = _k; + int dec = 0, m = _k - 1; + uint i = 0; double u = 0; + std::vector vecteursPointsControle (_nbPtsCtrlX); - std::vector vecteursPointsControle (_np1); - - for(u = _k - 1; u < _np1; u += _step){ - // Réinitialiser dec et i ? - while(u > _vecteurNodal[i]){ + // Parcours de u + for(u = _vecteurNodal[m]; u <= _vecteurNodal[_nbPtsCtrlX]; u += _stepX){ + dec = 0; + // Calcul du décalage + for(int i = _k; u > _vecteurNodal[i]; ++i) ++dec; - ++i; - } - // int i à virer ? + // Récupération des k points de contrôles nécessaires à la floraison for(int i = 0; i < _k; i++){ vecteursPointsControle[i] = _pointsDeControle[dec + i]; } + // Appel de la floraison récursive glm::vec3 newVertex = floraison(u, dec, _k, vecteursPointsControle); - //std::cout << newVertex.x << " " << newVertex.y << " " << newVertex.z << std::endl; - _vertices.push_back(newVertex); + + // Sauvegardes des paramètres de la B-spline + _vertices.insert(_vertices.end(), {newVertex.x, newVertex.y, newVertex.z}); + _normals.insert(_normals.end(), {1, -1, -1}); + _indices.insert(_indices.end(), {i, i, ++i}); } + + // Enlever la ligne d'indices en trop + for(int i = 0; i < 3; ++i) + _indices.pop_back(); + + // Ajouter le polygone de controle aux vecteurs + for(unsigned int i = 0; i < _pointsDeControle.size(); ++i) { + _indices.insert(_indices.end(), {static_cast(_vertices.size())/3, static_cast(_vertices.size()/3), static_cast(_vertices.size())/3+1}); + _vertices.insert(_vertices.end(), {_pointsDeControle[i].x, _pointsDeControle[i].y, _pointsDeControle[i].z}); + _normals.insert(_normals.end(), {0, 0, 0}); + } + + // Enlever la ligne d'indices en trop + for(int i = 0; i < 3; ++i) + _indices.pop_back(); +} + + +void BSpline::calculerSpline2D() +{ } glm::vec3 BSpline::floraison(float u, int dec, int k, std::vector vecteursPointsControle) { - if(k == 0) + if(k <= 1) return vecteursPointsControle.front(); - for(int i = 0; i < k - 1; ++i) + + for(int i = 0; i < k - 1; ++i) { + float max = _vecteurNodal[dec + k + i]; + float min = _vecteurNodal[dec + 1 + i]; vecteursPointsControle[i] = - (((_vecteurNodal[dec + k + i] - u) / (_vecteurNodal[dec + k + i] - _vecteurNodal[dec + 1 + i])) * vecteursPointsControle[i]) * - (((u - _vecteurNodal[dec + 1 + i]) / (_vecteurNodal[dec + k + i] - _vecteurNodal[dec + 1 + i])) * vecteursPointsControle[i+1]); - floraison(u, dec+1, k-1, vecteursPointsControle); + ((( max - u) / (max - min)) * vecteursPointsControle[i]) + + ((( u - min) / (max - min)) * vecteursPointsControle[i+1]); + } + + return floraison(u, dec+1, k-1, vecteursPointsControle); } -std::vector const BSpline::getVertices() +void BSpline::construirePolygone(EPolygone typePolygone, int nbPtsCtrlX, int nbPtsCtrlZ) { - std::vector vertices; - // Ajout des points de contrôle - for(glm::vec3 point: _pointsDeControle) - vertices.insert(vertices.end(), {point.x, point.y, point.z}); + // Intervalle pour afficher dans le repère caméra + float xMin = -3, xMax = 3; + float yMin = -2, yMax = 2; + float zMin = -3, zMax = -6; - // Ajout des points issus de la floraison - for(glm::vec3 point: _vertices) - vertices.insert(vertices.end(), {point.x, point.y, point.z}); + switch (typePolygone) { + case EPolygone::FIXE2D: + _pointsDeControle.push_back(glm::vec3(-2, 0, -5)); + _pointsDeControle.push_back(glm::vec3(-1, 0, -5)); + _pointsDeControle.push_back(glm::vec3(-1, 1, -5)); + _pointsDeControle.push_back(glm::vec3( 1, 1, -5)); + _pointsDeControle.push_back(glm::vec3( 1, 0, -5)); + _pointsDeControle.push_back(glm::vec3( 2, 0, -5)); + _nbPtsCtrlX = 6; + _nbPtsCtrlZ = 0; + break; - return vertices; + case EPolygone::RANDOM2D: { + float x, y, z; + for(int i = 0; i < nbPtsCtrlX; ++i) { + //x = xMin + static_cast (rand()) /( static_cast (RAND_MAX/(xMax-xMin))); + x = (i * xMin + (nbPtsCtrlX - i) * xMax) / (xMax - xMin); + y = yMin + static_cast (rand()) /( static_cast (RAND_MAX/(yMax-yMin))); + z = zMin + static_cast (rand()) /( static_cast (RAND_MAX/(zMax-zMin))); + _pointsDeControle.push_back(glm::vec3(x, y, z)); + } + _nbPtsCtrlX = _pointsDeControle.size(); + _nbPtsCtrlZ = 0; + break; + } + + case EPolygone::GAUSSIEN3D: { + // Sigma = 1.0f + float r, s = 2.0f; + for(int x = - (nbPtsCtrlX / 2) + 1; x < nbPtsCtrlX / 2; ++x) { + for(int z = - (nbPtsCtrlZ / 2) + 1; x < nbPtsCtrlZ / 2; ++x) { + r = sqrt(x * x + z * z); + _pointsDeControle.push_back(glm::vec3( x, (exp(-(r * r) / s)) / (M_PI * s), z)); + } + } + _nbPtsCtrlX = nbPtsCtrlX - 1 - (nbPtsCtrlX % 2); + _nbPtsCtrlZ = nbPtsCtrlZ - 1 - (nbPtsCtrlZ % 2); + break; + } + + case EPolygone::FIXE3D: { + float x, y, z; + for(int i = 0; i < nbPtsCtrlX; ++i) { + for(int j = 0; j < nbPtsCtrlZ; ++j) { + x = (i * xMin + (nbPtsCtrlX - i) * xMax) / (xMax - xMin); + y = fmod(x + z, 3); + z = (j * zMin + (nbPtsCtrlZ - j) * zMax) / (zMax - zMin); + _pointsDeControle.push_back(glm::vec3(x, y, z)); + } + } + _nbPtsCtrlX = nbPtsCtrlX; + _nbPtsCtrlZ = nbPtsCtrlZ; + break; + } + + case EPolygone::RANDOM3D: { + float x, y, z; + for(int i = 0; i < nbPtsCtrlX; ++i) { + for(int j = 0; j < nbPtsCtrlZ; ++i) { + x = (i * xMin + (nbPtsCtrlX - i) * xMax) / (xMax - xMin); + y = yMin + static_cast (rand()) /( static_cast (RAND_MAX/(yMax-yMin))); + z = (j * zMin + (nbPtsCtrlZ - j) * zMax) / (zMax - zMin); + _pointsDeControle.push_back(glm::vec3(x, y, z)); + } + } + _nbPtsCtrlX = nbPtsCtrlX; + _nbPtsCtrlZ = nbPtsCtrlZ; + break; + } + + default: + std::cerr << "Type de polygone inconnu" << std::endl; + break; + } } -std::vector const BSpline::getNormals() +void BSpline::construireVecteurNodal(EVecteurNodal typeVecteur) { - std::vector normals; - for(glm::vec3 point: _pointsDeControle) - normals.insert(normals.end(), {point.x, point.y, point.z}); - // Ajout des normales des points issus de la floraison - for(glm::vec3 point: _vertices) - normals.insert(normals.end(), {point.x, point.y, point.z}); + switch (typeVecteur) { + case EVecteurNodal::UNIFORME: + for(int i = 0; i <= _k + _nbPtsCtrlX; ++i) { + _vecteurNodal.push_back(i); + } + break; + case EVecteurNodal::OUVERTUNIFORME: + for(int i = 0; i <= _k + _nbPtsCtrlX; ++i) { + if (i < _k) + _vecteurNodal.push_back(0); + else if (i > _nbPtsCtrlX) + _vecteurNodal.push_back(_nbPtsCtrlX - _k + 1); + else + _vecteurNodal.push_back(i - _k + 1); + std::cout << _vecteurNodal.back() << " "; + } + break; + case EVecteurNodal::QUELCONQUE: { + int r = 0; + _vecteurNodal.push_back(0); + for(int i = 1; i <= _k + _nbPtsCtrlX; ++i) { + r = rand() / (RAND_MAX/5); + _vecteurNodal.push_back(_vecteurNodal.back() + r); + } + break; + } + default: + std::cerr << "Type de vecteur nodal inconnu" << std::endl; + break; + } - return normals; -} - -std::vector const BSpline::getIndices() -{ - std::vector indices; - for(uint i = 0; i < _pointsDeControle.size() - 1; ++i) - indices.insert(indices.end(), {i, i, i+1}); - // Ajout des indices pour les points issus de la floraison - for(uint i = 0; i < _vertices.size() - 1; ++i) - indices.insert(indices.end(), {i, i, i+1}); - - return indices; } diff --git a/src/bspline.h b/src/bspline.h index 5f1d392..534492a 100644 --- a/src/bspline.h +++ b/src/bspline.h @@ -7,22 +7,53 @@ class BSpline { + public: - BSpline(int k = 2, double step = 0.1, int np1 = 6); - std::vector const getVertices(); - std::vector const getNormals(); - std::vector const getIndices(); + enum class ESpline {SPLINE1D, SPLINE2D}; + enum class EPolygone {FIXE2D, RANDOM2D, GAUSSIEN3D, FIXE3D, RANDOM3D}; + enum class EVecteurNodal {UNIFORME, OUVERTUNIFORME, QUELCONQUE}; + + BSpline(ESpline typeSpline = ESpline::SPLINE1D, + int k = 3, + EPolygone typePolygone = EPolygone::RANDOM2D, + EVecteurNodal typeVecteur = EVecteurNodal::UNIFORME, + int nbPtsCtrlX = 10, + int nbPtsCtrlZ = 10, + float stepX = 0.1, + float stepY = 0.1); + std::vector const & getVertices() const {return _vertices;} + std::vector const & getNormals() const {return _normals;} + std::vector const & getIndices() const {return _indices;} + private: - std::vector _vecteurNodal; + // Vecteurs std::vector _pointsDeControle; - int _k; - int _np1; - double _step; + std::vector _vecteurNodal; - std::vector _vertices; + // Paramètres + int _k, _nbPtsCtrlX, _nbPtsCtrlZ; + float _stepX, _stepY; - void computeSpline(); + ESpline _typeSpline; + EPolygone _typePolygone; + EVecteurNodal _typeVecteur; + + // Résultats + std::vector _vertices; + std::vector _normals; + std::vector _indices; + + // B-spline + void calculerSpline1D(); + void calculerSpline2D(); + // Floraison récursive glm::vec3 floraison(float u, int dec, int k, std::vector vecteursPointsControle); + + // Polygone + void construirePolygone(EPolygone typePolygone, int nbPtsCtrlX, int nbPtsCtrlZ); + // Vecteur Nodal + void construireVecteurNodal(EVecteurNodal typeVecteur); + }; #endif // BSPLINE_H diff --git a/src/hello_spline/hellospline.cpp b/src/hello_spline/hellospline.cpp index a43403f..dba5a9a 100644 --- a/src/hello_spline/hellospline.cpp +++ b/src/hello_spline/hellospline.cpp @@ -10,8 +10,24 @@ SimpleSpline::SimpleSpline(int width, int height, MainWindow* w) : Scene(width, _lastVertex = _w->vertexShader; _lastFragment = _w->fragmentShader; - // LOAD B-SPLINE - BSpline bspline1D = BSpline(); + /* Génération B-SPLINE - Paramètres: + * Type de BSpline (1D / 2D) + * Ordre k + * Type de Polygone de contrôle (2D: fixé, random / 3D: gaussien, fixé, random) + * Type de vecteur nodal (Uniforme / Ouvert uniforme / Quelconque) + * + * Pas pour delta u et Pas pour delta v */ + BSpline bspline1D = BSpline( + BSpline::ESpline::SPLINE1D, + 3, + BSpline::EPolygone::RANDOM2D, + BSpline::EVecteurNodal::UNIFORME, + 5, + 5, + 0.1, + 0.1 + ); + _vertices = bspline1D.getVertices(); _indices = bspline1D.getIndices(); _normals = bspline1D.getNormals(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 07d5312..127bdb0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -98,6 +98,6 @@ void MainWindow::addShaders() { } // Set default shaders - vertexShader = vertexShaders.constBegin().key(); - fragmentShader = fragmentShaders.constBegin().key(); + vertexShader = vertexShaders.firstKey(); + fragmentShader = fragmentShaders.lastKey(); } diff --git a/src/mainwindow.h b/src/mainwindow.h index ae482ab..3be8f2e 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -21,7 +21,7 @@ public: QMap vertexShaders; QMap fragmentShaders; - bool culling = true; + bool culling = false; private slots: void on_action_Version_OpenGL_triggered(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 02ea235..d057a2e 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -96,7 +96,7 @@ true - true + false Toggle backface culling diff --git a/src/scene.cpp b/src/scene.cpp index 540faca..e91ce45 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -6,6 +6,7 @@ Scene::Scene(int width, int height, MainWindow* w) : _width(width), _height(heig glEnable(GL_DEPTH_TEST); glViewport(0, 0, width, height); glPointSize(5.0f); + _drawfill = 2; } Scene::~Scene() { diff --git a/src/scene.h b/src/scene.h index f180f3c..ce7ad61 100644 --- a/src/scene.h +++ b/src/scene.h @@ -32,7 +32,7 @@ protected: private: // Rendering mode - int _drawfill = 1; + int _drawfill; };