Flawless BSpline 1D

This commit is contained in:
ao 2018-10-09 23:29:30 +02:00
parent 060aaeb0bf
commit 6c39ee710a
8 changed files with 262 additions and 80 deletions

View File

@ -1,97 +1,231 @@
#include "bspline.h"
#include <cmath>
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)
{
// Simple vérification
switch (typeSpline) {
case ESpline::SPLINE1D:
assert(k <= nbPtsCtrlX);
break;
case ESpline::SPLINE2D:
assert(k <= nbPtsCtrlX && k <= nbPtsCtrlZ);
break;
}
// 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
_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;
}
}
void BSpline::calculerSpline1D()
{
// Init
int dec = 0, m = _k - 1;
uint i = 0;
double u = 0;
std::vector<glm::vec3> vecteursPointsControle (_nbPtsCtrlX);
// 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;
// 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);
// 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<unsigned int>(_vertices.size())/3, static_cast<unsigned int>(_vertices.size()/3), static_cast<unsigned int>(_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<glm::vec3> vecteursPointsControle)
{
if(k <= 1)
return vecteursPointsControle.front();
for(int i = 0; i < k - 1; ++i) {
float max = _vecteurNodal[dec + k + i];
float min = _vecteurNodal[dec + 1 + i];
vecteursPointsControle[i] =
((( max - u) / (max - min)) * vecteursPointsControle[i]) +
((( u - min) / (max - min)) * vecteursPointsControle[i+1]);
}
return floraison(u, dec+1, k-1, vecteursPointsControle);
}
void BSpline::construirePolygone(EPolygone typePolygone, int nbPtsCtrlX, int nbPtsCtrlZ)
{
// Intervalle pour afficher dans le repère caméra
float xMin = -3, xMax = 3;
float yMin = -2, yMax = 2;
float zMin = -3, zMax = -6;
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;
computeSpline();
}
void BSpline::computeSpline()
{
// Init
int dec = 0, i = _k;
double u = 0;
std::vector<glm::vec3> vecteursPointsControle (_np1);
for(u = _k - 1; u < _np1; u += _step){
// Réinitialiser dec et i ?
while(u > _vecteurNodal[i]){
++dec;
++i;
case EPolygone::RANDOM2D: {
float x, y, z;
for(int i = 0; i < nbPtsCtrlX; ++i) {
//x = xMin + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(xMax-xMin)));
x = (i * xMin + (nbPtsCtrlX - i) * xMax) / (xMax - xMin);
y = yMin + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(yMax-yMin)));
z = zMin + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(zMax-zMin)));
_pointsDeControle.push_back(glm::vec3(x, y, z));
}
_nbPtsCtrlX = _pointsDeControle.size();
_nbPtsCtrlZ = 0;
break;
}
// int i à virer ?
for(int i = 0; i < _k; i++){
vecteursPointsControle[i] = _pointsDeControle[dec + i];
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;
}
glm::vec3 newVertex = floraison(u, dec, _k, vecteursPointsControle);
//std::cout << newVertex.x << " " << newVertex.y << " " << newVertex.z << std::endl;
_vertices.push_back(newVertex);
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 <float> (rand()) /( static_cast <float> (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;
}
}
glm::vec3 BSpline::floraison(float u, int dec, int k, std::vector<glm::vec3> vecteursPointsControle)
void BSpline::construireVecteurNodal(EVecteurNodal typeVecteur)
{
if(k == 0)
return vecteursPointsControle.front();
for(int i = 0; i < k - 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);
}
std::vector<GLfloat> const BSpline::getVertices()
{
std::vector<GLfloat> vertices;
// Ajout des points de contrôle
for(glm::vec3 point: _pointsDeControle)
vertices.insert(vertices.end(), {point.x, point.y, point.z});
// Ajout des points issus de la floraison
for(glm::vec3 point: _vertices)
vertices.insert(vertices.end(), {point.x, point.y, point.z});
return vertices;
}
std::vector<GLfloat> const BSpline::getNormals()
{
std::vector<GLfloat> 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});
return normals;
}
std::vector<GLuint> const BSpline::getIndices()
{
std::vector<GLuint> 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;
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;
}
}

View File

@ -7,22 +7,53 @@
class BSpline
{
public:
BSpline(int k = 2, double step = 0.1, int np1 = 6);
std::vector<GLfloat> const getVertices();
std::vector<GLfloat> const getNormals();
std::vector<GLuint> 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<GLfloat> const & getVertices() const {return _vertices;}
std::vector<GLfloat> const & getNormals() const {return _normals;}
std::vector<GLuint> const & getIndices() const {return _indices;}
private:
std::vector<float> _vecteurNodal;
// Vecteurs
std::vector<glm::vec3> _pointsDeControle;
int _k;
int _np1;
double _step;
std::vector<float> _vecteurNodal;
std::vector<glm::vec3> _vertices;
// Paramètres
int _k, _nbPtsCtrlX, _nbPtsCtrlZ;
float _stepX, _stepY;
void computeSpline();
ESpline _typeSpline;
EPolygone _typePolygone;
EVecteurNodal _typeVecteur;
// Résultats
std::vector<GLfloat> _vertices;
std::vector<GLfloat> _normals;
std::vector<GLuint> _indices;
// B-spline
void calculerSpline1D();
void calculerSpline2D();
// Floraison récursive
glm::vec3 floraison(float u, int dec, int k, std::vector<glm::vec3> vecteursPointsControle);
// Polygone
void construirePolygone(EPolygone typePolygone, int nbPtsCtrlX, int nbPtsCtrlZ);
// Vecteur Nodal
void construireVecteurNodal(EVecteurNodal typeVecteur);
};
#endif // BSPLINE_H

View File

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

View File

@ -98,6 +98,6 @@ void MainWindow::addShaders() {
}
// Set default shaders
vertexShader = vertexShaders.constBegin().key();
fragmentShader = fragmentShaders.constBegin().key();
vertexShader = vertexShaders.firstKey();
fragmentShader = fragmentShaders.lastKey();
}

View File

@ -21,7 +21,7 @@ public:
QMap<QString, std::string> vertexShaders;
QMap<QString, std::string> fragmentShaders;
bool culling = true;
bool culling = false;
private slots:
void on_action_Version_OpenGL_triggered();

View File

@ -96,7 +96,7 @@
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="text">
<string>Toggle backface culling</string>

View File

@ -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() {

View File

@ -32,7 +32,7 @@ protected:
private:
// Rendering mode
int _drawfill = 1;
int _drawfill;
};