Accueil > > > Envi3D/OpenGLWidget.cpp
BASE/MOTEUR 3D EN QT/OPENGL (COMPLET ET FONCTIONNEL!) POUR UN TRÈS PROCHAIN JEU 3D
Envi3D/OpenGLWidget.cpp
Informations sur ce code source
Bonjour à tous,
Voici un moteur 3D gérant les textures tous formats (supporté par QT) et contient un loader de fichier .obj que j'ai écrit personnellement.
Il permet d'illustrer l'utilisation de deux QGLWidget en même temps et comment se servir de
Fichier : Envi3D/OpenGLWidget.cpp
Nombre de lignes : 514 lignes
Afficher ce fichier en plein écran
- #include "OpenGLWidget.h"
- #define VUEPRINCIPALE 0
- #define MINICARTE 1
- OpenGLWidget::OpenGLWidget ( QWidget *parent, int largeur, int hauteur, Personnage *joueur, Coord3D positionCamera, Coord3D targetCamera, int tailleSolX, int tailleSolY, Objet *listeObjets[], int nombreObjets, int typeCamera, QString nomDeClasse) : QGLWidget ( parent ) //le ": QGLWidget (parent) sert a appeler le constructeur de parent(obligatoire)
- {
- _vueActive = true;
- _typeDeCamera = typeCamera;// va determiner si la camera est fixe ou si il faut appeler getPosition (du joueur) et getCibleCamera pour positionner la camera
- _nomDeClasse = nomDeClasse;
- p_joueur = joueur;
- _tailleSolX = tailleSolX;
- _tailleSolY = tailleSolY;
- _nombreObjets = nombreObjets;
- for (int i=0 ; i < _nombreObjets ; i++)
- {
- p_listeObjets[i] = listeObjets[i];
- }
- _positionCamera = positionCamera;
- _cibleCamera = targetCamera;
- //setMouseTracking(true);
- //qDebug() << hasMouseTracking();
- //QMessageBox::critical(this, tr("Snake3D"), (_nomDeClasse), QMessageBox::Ok);
- setFixedSize ( largeur, hauteur );
- setFormat ( QGLFormat ( QGL::DoubleBuffer | QGL::DepthBuffer ) );
- //qDebug() << "Zconstructeur = " << p_listeObjets[1]->getZ();
- a=0; //angle de rotation de la lumiere LIGHT0
- qDebug() << "+ Creation du GLwidget : " << _nomDeClasse << " : OK";
- }
- void OpenGLWidget::initializeGL()
- {
- qglClearColor ( Qt::black );
- /////////////////////Brouillard/////////////////////////////////////
- /*
- GLfloat fogColor[4]= {0.9f, 0.9f, 0.9f, 1.0f};
- glClearColor ( 0.9f,0.9f,0.9f,1.0f ); // We'll Clear To The Color Of The Fog ( Modified )
- glFogi ( GL_FOG_MODE, GL_LINEAR );
- glFogfv ( GL_FOG_COLOR, fogColor ); // Set Fog Color
- //glFogf ( GL_FOG_DENSITY, 0.05f // How Dense Will The Fog Be (just pour le mode EXP et EXP_2)
- glHint ( GL_FOG_HINT, GL_NICEST ); // Fog Hint Value
- glFogf ( GL_FOG_START, 10.0f ); // Fog Start Depth //just for LINEAR
- glFogf ( GL_FOG_END, 60.0f ); // Fog End Depth
- glEnable ( GL_FOG ); // Enables GL_FOG
- */
- ////////////////////////////////////////////////////////////////////
- /////////////////////Eclairage/////////////////////////////////////
- float colorWhite[4] = {1.0f,1.0f,1.0f,1.0f};
- float ambientColor[4] = {0.35f,0.35f,0.35f,1.0f};
- //float colorEmission[4] = {0.0f,0.0f,0.0f,1.0f};
- glEnable(GL_DEPTH_TEST); // Active le test de profondeur
- glEnable(GL_LIGHTING); // Active l'éclairage
- glEnable(GL_LIGHT0); // Active light0
- glLightfv(GL_LIGHT0,GL_AMBIENT,ambientColor);
- glLightf(GL_LIGHT0,GL_LINEAR_ATTENUATION ,0.1f);
- glEnable(GL_LIGHT1); //le spot qui eclaire le sol sous la lampe de plafond
- glLightfv( GL_LIGHT1, GL_DIFFUSE, colorWhite );
- glLightfv( GL_LIGHT1, GL_SPECULAR, colorWhite );
- glLightf( GL_LIGHT1, GL_SPOT_CUTOFF, 90.0f ); //angle du spot
- glLightf( GL_LIGHT1, GL_SPOT_EXPONENT, 3.0f); //attenuation, pour flouter les bord de la tache de lumière
- glEnable(GL_LIGHT2); //le spot qui eclaire l'interieur de la lampe
- glLightfv( GL_LIGHT2, GL_DIFFUSE, colorWhite );
- glLightfv( GL_LIGHT2, GL_SPECULAR, colorWhite );
- glLightf( GL_LIGHT2, GL_SPOT_CUTOFF, 90.0f );
- glLightf( GL_LIGHT2, GL_SPOT_EXPONENT, 3.0f);
- glEnable(GL_LIGHT3); // Active light3, qui va suivre le projectile lors du tir
- glLightfv( GL_LIGHT3, GL_DIFFUSE, colorWhite );
- glLightfv( GL_LIGHT3, GL_SPECULAR, colorWhite );
- glLightf(GL_LIGHT3,GL_LINEAR_ATTENUATION ,0.1f);
- glDisable(GL_LIGHT3);
- /*config reflection lumière sur les matériaux*/
- int MatSpec [4] = {1,1,1,1};
- float ambient[4] = {0.55f,0.55f,0.55f,1.0f};
- glMaterialiv(GL_FRONT_AND_BACK,GL_SPECULAR,MatSpec);
- glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
- glMateriali(GL_FRONT_AND_BACK,GL_SHININESS,100);
- /*fin config lum*/
- ///////////////////////////////////////////////////////////////////
- /////////////////////Texture des divers objets du joueur//////////////
- texturesGun1 = loadTexture ( QString ( "pics/metalGun1.png" ), true);
- texturesGun2 = loadTexture ( QString ( "pics/metalGun2.png" ), true);
- textureSol = loadTexture ( QString ( "pics/floor.png" ), true);
- textureJoueur = loadTexture ( QString ( "pics/whisp.png" ), true);
- textureVueInactive = loadTexture ( QString ( "pics/vueInactive.png" ), true);
- /////////////////////////////////////////////////////////////////////
- for (int i=0 ; i < _nombreObjets ; i++)
- {
- //qDebug() << "appel generation des mipmaps";
- p_listeObjets[i]->genererTextureOpenGL(true);
- //qDebug() << "fin generation des mipmaps";
- }
- p_joueur->genererTextureOpenGL(true);
- qDebug() << "+ Initialisation OpenGL de" << _nomDeClasse << ": OK";;
- }
- GLuint OpenGLWidget::loadTexture ( QString filename, bool useMipMap)
- {
- QImage baseTexture;
- QImage interTexture;
- GLuint finalTexture;
- bool etatChargement = baseTexture.load ( filename, "PNG" ); //chargement de l'image, etatChargement contient true si cest chargé
- //qDebug() << filename << baseTexture.hasAlphaChannel();
- if (etatChargement == false)
- {
- qDebug() << "----->ERREUR 02 ; Chargement textureGun = FAILED";
- }
- interTexture = QGLWidget::convertToGLFormat ( baseTexture ); //transformation et renversement de l'image
- glGenTextures ( 1, &finalTexture ); //generation de la texture openGL, Ã ce niveau ont pourrait renvoyer finalTexture
- glBindTexture ( GL_TEXTURE_2D, finalTexture );
- if ( useMipMap )
- {
- gluBuild2DMipmaps ( GL_TEXTURE_2D, 3, interTexture.width(), interTexture.height(), GL_RGBA, GL_UNSIGNED_BYTE,
- interTexture.bits() );//creation des 3 mipmaps (adapte a chaque distance)
- glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); //ajout du filtre trilineaire pour le "tres beau rendu"
- glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); //filtre lineaire pour longue distance
- }
- else
- {
- glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); //ajout seulement d'un filtre lineaire
- glTexImage2D ( GL_TEXTURE_2D, 0, 3, interTexture.width(), interTexture.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, interTexture.bits() );
- }
- //qDebug() << "Chargement texture objet OpenGLWidget... fichierText ; " << filename << " | largeur = " << interTexture.width();
- return finalTexture; //on renvoie la texture
- }
- /////////////////////////////////////////////////////////////////////////////////////
- /*REPERE*/
- void OpenGLWidget::dessinerRepere()
- {
- glDisable ( GL_TEXTURE_2D );
- glEnable(GL_COLOR_MATERIAL);
- glLineWidth(8);
- glPushMatrix();
- glBegin(GL_LINES);
- glColor3ub(0,0,255); //axe X en Bleu
- glVertex3d(0,0,0);
- glVertex3d(2,0,0);
- glVertex3f(1.5 , 0 , 0.5); //les 2 trait du X
- glVertex3f(2 , 0 , 1.3);
- glVertex3f(1.5 , 0 , 1.3);
- glVertex3f(2 , 0 , 0.5);
- glColor3ub(0,255,0); //axe Y en Vert
- glVertex3d(0,0,0);
- glVertex3d(0,2,0);
- glVertex3f(0 , 1.5 , 1); //les 2 trait du Y
- glVertex3f(0 , 1.2 , 2);
- glVertex3f(0 , 1.6 , 2);
- glVertex3f(0 , 1.4 , 1.5);
- glColor3ub(255,0,0); //axe Z en Rouge;
- glVertex3d(0,0,0);
- glVertex3d(0,0,2);
- glVertex3f(0.2 , 0 , 2); //les 3 trait du Z
- glVertex3f(0.7 , 0 , 2);
- glVertex3f(0.7 , 0 , 2);
- glVertex3f(0.2 , 0 , 1.5);
- glVertex3f(0.2 , 0 , 1.5);
- glVertex3f(0.7 , 0 , 1.5);
- glColor3ub(255,255,255);
- glEnd();
- glPopMatrix();
- glDisable(GL_COLOR_MATERIAL);
- glEnable(GL_TEXTURE_2D);
- }
- void OpenGLWidget::ConversionVecteursVersAngles() //transforme les coordonnées X,Y,Z en _phi et _theta
- {
- //Calcul des angles à partir des coordonnees X,Y,Z :
- //Une coordonnee spherique est de forme (r, _phi, _theta)
- //Pour les coordonnees spherique (r,theta,phi) on a phi langle à partir de laxe vertical z
- //et theta langle à partir de laxe x
- //r = racine( x² + y² + z² )
- //_phi = arcos ( Z / r)
- //_theta = arcos ( X / racine(X²+Y²) )
- //-La librairie <cmath> utilise les radians! C'est pour cela qu'il faut convertir à chaque fois les degrés...
- Coord3D _forward;
- _forward.X = _targetJoueur.X - (_positionJoueur.X+1);
- _forward.Y = _targetJoueur.Y - (_positionJoueur.Y+1);
- _forward.Z = _targetJoueur.Z - (_positionJoueur.Z+6);
- //qDebug() << "old_theta = " << _theta << " | _Phi = " << _phi;
- float r = sqrt(pow(_forward.X,2) + pow(_forward.Y,2) + pow(_forward.Z,2));
- _phi = ( acos(_forward.Z/r) *180/M_PI);
- //qDebug() << "r = " << r;
- float r_temp = sqrt(pow(_forward.X,2) + pow(_forward.Y,2));
- if (_forward.Y >= 0)
- _theta = ( (acos(_forward.X/r_temp)) *180/M_PI);
- else
- _theta = - ( (acos(_forward.X/r_temp)) *180/M_PI);
- //qDebug() << "new_theta = " << _theta << " | _Phi = " << _phi;
- }
- void OpenGLWidget::resizeGL ( int width, int height )
- {
- glViewport ( 0, 0, width, height );
- glMatrixMode ( GL_PROJECTION );
- glLoadIdentity();
- gluPerspective ( 70, ( float ) 640/480,0.5,200 );
- qDebug() << "+ Resize OpenGL de" << _nomDeClasse << ": OK";
- }
- /////////////////////////////////////////////////////////////////////////////////////
- void OpenGLWidget::paintGL()
- {
- if (_vueActive == true)
- {
- //qDebug() << _nomDeClasse + " : draw" ;
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- ////////////////////////////////////
- /////Placement de la camera//////
- ////////////////////////////////////
- _positionJoueur = (*p_joueur).getPosition();
- _targetJoueur = (*p_joueur).getCibleCamera();
- if (_typeDeCamera == VUEPRINCIPALE) //si cest la vue principale, la camera est fixee au joueur
- {
- _positionCamera.X = _positionJoueur.X +1;
- _positionCamera.Y = _positionJoueur.Y +1;
- _positionCamera.Z = _positionJoueur.Z +6;
- _cibleCamera = _targetJoueur;
- //qDebug() << "position camera =" << _positionCamera.X << _positionCamera.Y << _positionCamera.Z;
- //qDebug() << "target camera =" << _cibleCamera.X << _cibleCamera.Y << _cibleCamera.Z;
- gluLookAt(_positionCamera.X,_positionCamera.Y,_positionCamera.Z,_cibleCamera.X,_cibleCamera.Y,_cibleCamera.Z,0,0,1);
- }
- else if (_typeDeCamera == MINICARTE)
- {
- gluLookAt(_positionCamera.X,_positionCamera.Y,_positionCamera.Z,_cibleCamera.X,_cibleCamera.Y,_cibleCamera.Z,0,0,1);
- }
- ////////////////////////////////////
- /////Gestion des lumières///////////
- ////////////////////////////////////
- int light0Pos[4] = {0, 10, 1, 1};
- float spot1Pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- float spot1Dir[3] = {0.0f, 0.0f, -1.0f};
- float spot2Pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- float spot2Dir[3] = {0.0f, 0.0f, 10.0f};
- glDisable ( GL_TEXTURE_2D );
- glEnable(GL_COLOR_MATERIAL);
- glColor3ub(255,255,255);
- glPushMatrix();
- //La petite sphere qui représente la lumière
- glTranslated(24,26,3);
- glPushMatrix();
- glRotated(a,0,0,1);
- glPushMatrix();
- glTranslated(0,10.2,1); //10.2 etant maintenant la distance entre la grosse sphere et la petite
- GLUquadric* params = gluNewQuadric();
- gluQuadricDrawStyle(params,GLU_POINT);
- gluSphere(params,0.1,50,50);
- gluDeleteQuadric(params);
- glPopMatrix();
- //la lumière accroché à la petite sphere
- glLightiv(GL_LIGHT0,GL_POSITION,light0Pos);
- glPopMatrix();
- //et la sphere au centre
- GLUquadric* params2 = gluNewQuadric();
- gluQuadricDrawStyle(params2,GLU_FILL);
- gluSphere(params2,1,50,50);
- gluDeleteQuadric(params2);
- glPopMatrix();
- a+=1; //l'angle de rotation de la lumière
- // Et la LIGHT1 qui est un spot (dirigé vers la chaise)
- glPushMatrix();
- glTranslated(48,30,8);
- glLightfv( GL_LIGHT1, GL_POSITION, spot1Pos );
- glLightfv( GL_LIGHT1, GL_SPOT_DIRECTION, spot1Dir );
- glTranslated(0,0,-2); //et maintenant on eclaire l'interieur de la lampe pour le réalisme
- glLightfv( GL_LIGHT2, GL_POSITION, spot2Pos );
- glLightfv( GL_LIGHT2, GL_SPOT_DIRECTION, spot2Dir );
- glPopMatrix();
- glDisable(GL_COLOR_MATERIAL);
- //on place la lumiere sous le projectile de l'arme
- if (p_listeObjets[0]->getIsVisible() == true)
- {
- Coord3D positionProjectile = p_listeObjets[0]->getPosition();
- float spot3Pos[4] = {positionProjectile.X, positionProjectile.Y, positionProjectile.Z, 1.0f};
- glEnable(GL_LIGHT3);
- glLightfv( GL_LIGHT3, GL_POSITION, spot3Pos );
- }
- else
- {
- glDisable(GL_LIGHT3);
- }
- //////////////////////////////
- //Dessin de lenvironnement; //
- //////////////////////////////
- dessinerRepere();
- glEnable ( GL_TEXTURE_2D );
- ////On dessine le sol
- glBindTexture ( GL_TEXTURE_2D, textureSol );
- glBegin ( GL_TRIANGLES );
- for (int indice_y=0 ; indice_y <= _tailleSolY ; indice_y++)
- {
- for (int indice_x=0 ; indice_x <= _tailleSolX ; indice_x++)
- {
- glNormal3d (0,0,1);
- glTexCoord2d ( 0,0 ); glVertex3d ( indice_x, indice_y, 0 );
- glTexCoord2d ( 1,0 ); glVertex3d ( indice_x+1,indice_y,0 );
- glTexCoord2d ( 1,1 ); glVertex3d ( indice_x+1,indice_y+1,0 );
- glNormal3d (0,0,1);
- glTexCoord2d ( 1,1 ); glVertex3d ( indice_x+1,indice_y+1,0 );
- glTexCoord2d ( 0,1 ); glVertex3d ( indice_x,indice_y+1,0 );
- glTexCoord2d ( 0,0 ); glVertex3d ( indice_x, indice_y, 0 );
- }
- }
- glEnd();
- // On affiche maintenant tous les objets,
- // normalement il suffit d'appeler la fonction afficherObjet() de chaque objet.
- // Mais il faut d'abord dessiner ceux qui sont opaques, puis desactiver le z-buffer en ecriture, et dessiner
- // les face transparentes pour que les pixel transparent ne cache pas les objet derriere, et que ces faces
- // transparente soit caché par les opaque devant (c'est pour cette derniere raison qu'on ne desactive pas le DEPTH_TEST;
- int indexObjet = 0;
- vector< int > tableau(_nombreObjets,0);
- for (int i=0 ; i < _nombreObjets ; i++)
- {
- if (p_listeObjets[i]->getIsDead() == true)
- {
- tableau[indexObjet] = i;
- indexObjet++;
- }
- else
- p_listeObjets[i]->afficherObjet();
- //p_listeObjets[i]->dessinerBoundBox();
- }
- glDepthMask(GL_FALSE); //on desactive le z-buffer EN ECRITURE, sinon les face transparentes serait dessiné au dessus des opaques
- for (int i=0 ; i < indexObjet ; i++)
- {
- p_listeObjets[tableau[i]]->afficherObjet();
- }
- glDepthMask(GL_TRUE); //on le reactive
- //on dessine le joueur
- if (_typeDeCamera == MINICARTE) //On ne dessine le joueur que sur la minicarte
- {
- glPushMatrix();
- glTranslated(0,0,5);
- glEnable(GL_ALPHA_TEST); //canal alpha pour la transparence des .png
- glEnable(GL_BLEND); // Turn Blending On
- glColor4f(1.0f,1.0f,1.0f,0.5f); // Full brightness, 50% Alpha
- glBlendFunc(GL_SRC_ALPHA,GL_ONE);
- p_joueur->afficherObjet();
- glDisable(GL_ALPHA_TEST);
- glDisable(GL_BLEND); // Desactivation de la transparence
- glColor3ub(255,255,255);
- glPopMatrix();
- //(*p_joueur).dessinerCollisionBox();
- }
- if (_typeDeCamera == VUEPRINCIPALE) //On ne dessine l'arme du joueur que sur la vue princ
- {
- //Et l'arme du joueur, on vide le Zbuffer pour garder l'arme dessinée au dessus de tous les autres objets
- glClear (GL_DEPTH_BUFFER_BIT);
- //Gun
- glPushMatrix();
- glTranslated ( _positionJoueur.X+1,_positionJoueur.Y+1, _positionJoueur.Z+6 ); //on place le cylindre au niveau du personnage
- ConversionVecteursVersAngles();
- glRotated (_theta+90,0,0,1); //on lui fait faire une rotation
- glRotated (_phi,1,0,0);
- glTranslated ( 0,-1,0); //puis on le deplace vers le bas de lecran
- //Cylindre principale
- GLUquadric* paramsArme = gluNewQuadric();
- gluQuadricDrawStyle(paramsArme,GLU_FILL);
- glBindTexture(GL_TEXTURE_2D,texturesGun1);
- gluQuadricTexture(paramsArme,GL_TRUE);
- gluCylinder(paramsArme,0.3,0.3,3.5,20,1);
- //Cylindres secondaires
- glPushMatrix();
- glRotated (p_joueur->getAngleRotationArme(),0,0,1);
- glBindTexture(GL_TEXTURE_2D,texturesGun2);
- gluQuadricTexture(paramsArme,GL_TRUE);
- glPushMatrix();
- glTranslated (0,0.3,0);
- gluCylinder(paramsArme,0.1,0.1,3,20,1);
- glPopMatrix();
- glPushMatrix();
- glTranslated (0.3,0,0);
- gluCylinder(paramsArme,0.1,0.1,3,20,1);
- glPopMatrix();
- glPushMatrix();
- glTranslated (-0.3,0,0);
- gluCylinder(paramsArme,0.1,0.1,3,20,1);
- glPopMatrix();
- glPushMatrix();
- glTranslated (0,-0.3,0);
- gluCylinder(paramsArme,0.1,0.1,3,20,1);
- glPopMatrix();
- glPopMatrix();
- gluDeleteQuadric(paramsArme);
- //le viseur
- glDisable(GL_TEXTURE_2D);
- glLineWidth(2);
- glBegin ( GL_LINES );
- glColor3ub(50,50,50);
- glVertex3f ( -0.3,0,15 );
- glVertex3f ( +0.3,0,15 );
- glVertex3f ( 0,-0.3,15 );
- glVertex3f ( 0,+0.3,15 );
- glEnd();
- glPopMatrix();
- }
- }
- else //si isActif == false, on affiche juste un rectangle texture "inactif"
- {
- //qDebug() << "minicarte inactive";
- float ambient[4] = {1.0f,1.0f,1.0f,1.0f};
- glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- gluLookAt(0.4,-0.8,0.5,0.4,0,0.5,0,0,1);
- glEnable ( GL_TEXTURE_2D );
- glBindTexture ( GL_TEXTURE_2D, textureVueInactive );
- glBegin ( GL_QUADS );
- glNormal3d (-1,0,1);
- glTexCoord2d ( 0,0 ); glVertex3d ( 0,0,0 );
- glTexCoord2d ( 1,0 ); glVertex3d ( 1,0,0 );
- glTexCoord2d ( 1,1 ); glVertex3d ( 1,0,1 );
- glTexCoord2d ( 0,1 ); glVertex3d ( 0,0,1 );
- glEnd();
- }
- }
- void OpenGLWidget::setVueIsActive(bool active)
- {
- _vueActive = active;
- updateGL();
- }
|