IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenGL Discussion :

OpenGL et thread


Sujet :

OpenGL

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 109
    Par défaut OpenGL et thread
    Bonjour,

    Je souhaite modéliser un terrain très grand et l'afficher de façon optimisée. Pour ce faire, j'ai stocké toutes les données dans un fichier en binaire et je ne récupère que les vertex visibles en dynamique (par le frustum culling).

    Je souhaite donc charger ces données par un thread (avec sdl), seulement je ne vois pas trop comment m'y prendre car immanquablement, quand openGL va afficher les vertex, il va y avoir conflit quand je v supprimer les anciennes valeurs et mettre les nouvelles (ça m'arrive d'ailleurs).

    Autant je vois comment utiliser un mutex mais l'utiliser sur des données à afficher c'est pas vraiment conseillé si j'ai bien compris alors je ne peux pas mettre ma fonction d'affichage en thread ??.

    Le progamme fonctionne bien sans thread, hormis des ralentissements (logique, tout de même 2 à 300 groupes de vertex à charger à chaque fois).


    - void Map :: prepareDraw() = > teste le nouveau frustrum culling. S'il change alors le thread est lancé (sauf si c'est déjà en cours).

    - int Map :: thread() = > charge les nouveaux vertex + index, supprime les anciens. Doit être un thread

    - void Map :: draw() = > dessine ces vertex (par glDrawElements()). Fonction normale.


    Merci de votre aide.

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Effectivement il est déconseillé de mêler threads et APIs 3D. Normalement tu peux t'en passer, les algos de frustum culling sont suffisamment rapides pour que tu puisses les exécuter à chaque update sans plomber les perfs. Est-ce qu'au moins tu utilises une structure de partitionnement, par exemple un octree ?

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 109
    Par défaut
    Merci de ta réponse aussi rapide :p

    structure de partitionnement, par exemple un octree
    Euh ça je ne connais pas.
    Voilà comment je fais actuellement, sur de grandes map 3000*3000 (en fait je souhaite bien plus).

    Comme je lai dit plus ça fonctionne mais il y a quelques ralentissements (bon je suis un peu dur là .


    - Par l'algo de perlin, je génère mon fichier, les coordonnées, hauteurs et couleurs que je déduis par un mixage de plusieurs petites textures en fonction de la hauteur.
    J'ai renoncé à apliquer une texture par la méthode classique car soit ma texture est géante au départ et ça colle pas soit c'est trop lent car je suis obligé de la générer en dynamique.
    En gros dans ce fichier (205méga lol), pour chacun des 9millions de vertex j'ai :
    - les 3 couleurs en GLfloat
    - les 3 coordonnées, également en float

    A chaque frame :
    - je repère déjà les bornes limites par le frustrum culling. Mon terrain est coupé aléatoirement par groupes de 50 (j'essaie aussi de voir la valeur optimale) et je teste si le point et dedans ou pas. Tout de même 2500 passsages (50*50).
    J'en déduis l'encadrement sous forme d'un carré englobant ce frustrum composé de x_min / x_max (abscisse mini et maxi) , de z_min et z_max (ordonnée mini et maxi). Je ne tient pas compte de la hauteur (je mets la valeur médiane, zéro)


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    // Détermination des extrémums, 4 points limites pour dégrossir le terrain
    	int map_size = this->size;	// taille de la carte	
    	int foot = map_size/50;       // pas
     
    	// Liste de chaque extremum trouvé ...
    	std::list<int> abs;
    	std::list<int> ord;
     
     
    	// On découpe le terrain en carrés. Si un des points des extremité est dans le vue (fonction isInside)alors on va afficher cette portion de terrain
    	for (int k=0; k< map_size-foot;  k=k+foot)
    	{
    		for (int l=0; l< map_size-foot; l=l+foot)
    		{
    			Vecteur3D<GLfloat> u_left(l/DataMap::QUALITY,0,k/DataMap::QUALITY);						
    			Vecteur3D<GLfloat> u_right((l+foot)/DataMap::QUALITY,0,k/DataMap::QUALITY);						
    			Vecteur3D<GLfloat> d_left(l/DataMap::QUALITY,0,(k+foot)/DataMap::QUALITY);						
    			Vecteur3D<GLfloat> d_right((l+foot)/DataMap::QUALITY,0,(k+foot)/DataMap::QUALITY);						
     
    			if (isInside(u_left) || isInside(u_right) || isInside(d_left) || isInside(d_right))
    			{
    				abs.push_back(l);
    				abs.push_back(l+foot);
    				ord.push_back(k);
    				ord.push_back(k+foot);				
    			}						
    		}
    	}
     
    	// Tri 		
    	abs.sort();  // Toutes les abscisses que j'ai repérées et triées
    	ord.sort();  // Toutes les ordonnées repérées et triées
     
    	// On en déduit les valeurs limites trouvées. on met 300 en valeur mini qui correspond au maximum lointain visible (gluPerspective)	
    	this->thread_extremum[0] = abs.front();
    	this->thread_extremum[1] = Max(abs.back(),300);
    	this->thread_extremum[2] = ord.front();
    	this->thread_extremum[3] = Max(ord.back(),300);

    Si cette encadrement (stocké dans thread_extremum) diffère du précédent (stocké dans extremum) , alors je charge les nouvelles données dans un tableau comme ceci :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
     
    int Map :: loadData()
    {    
        int map_size = this->size;
     
        Uint32 x_min = this->thread_extremum[0];   // Les bornes de vues ici
        Uint32 x_max = this->thread_extremum[1];
        Uint32 z_min = this->thread_extremum[2];
        Uint32 z_max = this->thread_extremum[3];
     
        Uint32 delta_x = x_max-x_min;      // différences des abscisses
        Uint32 delta_z = z_max-z_min;      // différences des ordonnées
     
        Uint32 values_size = 6*delta_x*delta_z;   // nombre de données (6/ vertex)   
        Uint32 index_size = 6*(delta_x-1)*(delta_z-1);  // nombre d'indices
     
        // récupération des anciennes valeurs et indices (pour être effacées)
    	old_values = thread_values;
    	old_indices = thread_indices;
     
     
    	// Création des nouvelles valeurs et indices
       	  // Remplissage des nouveaux indices du thread, pour drawElements
        Uint32 pos = 0;  
        thread_indices = new GLuint[index_size];	
     
        for (Uint32 z=z_min; z< z_max-1; ++z)
         	 for (Uint32 x=x_min; x< x_max-1; ++x) 
    	 	 { 		 
     		    GLuint index = (z-z_min)*delta_x + x - x_min;
     
    		    thread_indices[pos] = index;
             	                 thread_indices[pos+1] = thread_indices[pos+3] = index +1;
             	                 thread_indices[pos+2] = thread_indices[pos+4] = index + delta_x;
             	                 thread_indices[pos+5] = index + delta_x + 1;
     
             	                 pos += 6;
     		 }	  
     
       std::cout << "Nouveaux indices affectés " << std::endl;
     
       /* Création du tableau de valeurs. Le fichier étant ordonné, c'est  relativement simple */
       thread_values = new GLfloat[values_size]; 
     
       std::ifstream r_file("datamap.txt",std::ios_base::binary);
       for (Uint32 z = z_min; z < z_max; ++z)
       {
       	   Uint32 first_value = 6*(z*map_size + x_min);
     
                    r_file.seekg(sizeof(GLfloat)*first_value,std::ios_base::beg);
       	   r_file.read(reinterpret_cast<char*>(&thread_values[6*delta_x*(z-z_min)]),sizeof(GLfloat)*6*delta_x);   	   
       }
     
       r_file.close();
     
       std::cout << "Nouvelles valeurs affectées " << std::endl;
     
      // Voici les nouveaux tableaux prêts à être envoyé à glDrawElements   this->values = thread_values;
       this->indices = thread_indices;
     
       // Voici les nouveaux extremum		                   
       this->extremum[0] = this->thread_extremum[0];
       this->extremum[1] = this->thread_extremum[1];
       this->extremum[2] = this->thread_extremum[2];
       this->extremum[3] = this->thread_extremum[3];
     
     
       // Suppression des anciennes valeurs
       if (old_values)
       	  delete [] old_values;     
       old_values = 0;
     
       if (old_indices)  
       	  delete [] old_indices;
       old_indices = 0;
     
       this->thread_is_on = false;
       std::cout << "Fin du thread" << std::endl;
     
       return 0;  // Valeur de retour bidon


    Ensuite il ne reste qu'à dessiner le tout ...


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    // Dessin de la map
    int Map :: draw()
    {
    	// Si on a pas de valeurs .. on sait jamais
        if (!this->values || !this->indices)
    	   return 0;
     
    	glDisable(GL_TEXTURE_2D);	// Sert à rien ici
     
    	Uint32 index_size = 6*(this->extremum[1]-this->extremum[0]-1)*(this->extremum[3]-this->extremum[2]-1);	
     
    	// On dessine les vertex
    	glInterleavedArrays(GL_C3F_V3F,0,this->values);  
    	glDrawElements(GL_TRIANGLES,index_size,GL_UNSIGNED_INT,this->indices);
     
    	glEnable(GL_TEXTURE_2D);	 // On le remet
     
    	return 0;
    }

  4. #4
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Tu devrais vraiment te pencher sur les structures de partitionnement, et notamment les octrees ou quadtrees dans ton cas
    http://jeux.developpez.com/faq/3d/?page=partitionnement

  5. #5
    Rédacteur
    Avatar de bafman
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    2 574
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Novembre 2003
    Messages : 2 574
    Par défaut
    en fait, tu a interet à decouper ton terrain en sous cases.
    chaque case peut avoir plusieurs niveau de details que tu stock dans tes fichier du moins detaillé (un simple quad par exemple) au plus detaillé.
    avec ca, quand tu te deplace sur ton terrain et que tu detecte qu'une case est visible, tu lance le thread de chargement de la case.
    au cours du chargement, comme tu commence par charger les version les moins détaillé, tu as rapidement des données à envoyé à la carte graphique, et, au fur et a mesure que tu t'approche de ta case, le thread aura chargé des données plus detaillées.

    bon ca rest quand même super bourrin à faire comme truc, et si tu veut plus d'info, tu peut regarder ce qui se passe dans le paging landscape plugin pour ogre qui en gros fait ce genre de truc...
    * Il est infiniment plus simple de faire rapidement un code qui marche que de faire un code rapide qui marche
    * pour faciliter les recherches, n'oubliez pas de voter pour les réponses pertinentes
    Mes articles

  6. #6
    Membre chevronné
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 366
    Par défaut
    Il y a deux choses a differencier dans le probleme :

    -le chargement des donnees du disque dur vers la memoire CPU

    -le transfert des donnees de la memoire GPU vers la memoire CPU.


    La seconde operation ne penalise pas trop la machine si elle n est pas faite trop souvent (cela doit etre le cas)

    Par contre, le chargement disque dur est infiniement plus long. Ce traitement devrait etre fait dans un thread secondaire. Une fois l operation terminee, il avertira le thread primaire (qui se reserve l acces a l API openGL) que les donnees sont dispo (semaphore , variable partagee testee a chaque passage dans la boucle principale)

    Donc le chargement dynamique ne devrait pas trop penaliser la machine. Il faut toutefois veiller a ce que le thread principal responsable de l affichage soit capable d'afficher un terrain partiellement (quand les donnees issues du disque dur ne sont pas encore dispo), sinon les thread deviennent serialises, et tu perds tout les avantages du multithreading

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    109
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2005
    Messages : 109
    Par défaut
    Ben ce qui pénalise surtout c'est le nombre de vertex à afficher.
    Sur un terrain immense, je suis obligé de tout calculer avant et de tout stocker. J'ai pas trouvé de moyen efficace d'appliquer des textures (soit trop grande, et en dynamique c'est vraiment lent) ce qui grossit le fichier.

    Comme indiqué j'ai au moins 10millions de vertex (sur un terrain de 3000*3000).

    J'ai regardé le tuto (merci Laurent) sur le octree, j'ai décidé de m'en inspirer en le combinant avec le frustum culling.

    - Au départ je détermine le frustrum.
    - Ensuite je détermine par système d'équation (intersection du plan lointain avec le plan gauche etc .... ) les coordonnées extrêmes que j'arrondis à un carré
    - Je découpe ce carré en plusieurs parties et j'en déduis la partie du terrain à afficher (à affiner). (2)
    - Je charge les parties du fichiers correspondants (à coup de reinterpret_cast), ce qui correspond à environ 4 ou 5000 vertex maxi le tout en tableau d'éléments ce qui est largement acceptable.

    C'est déjà beaucoup mieux que de boucler sur tout le terrain au départ comme je faisais (idiot lol).

    L'avantage c'est que la vitesse d'affichage de dépend presque plus de la taille du terrain et actuellement c'est fluide bien que (2) ne soit pas encore optimisé.

    IL ne me reste plus qu'à précalculer les normales.

    Je ferai un topo plus précis quand je serai fin prêt


    PS : Pour les thread, la seule solution que j'avais trouvé m'obligeait en plus à faire un autre tableau temporaire.
    Et puis j'ai renoncé quand j'ai vu quand il était très déconseillé et inutile de passer par là dès qu'il s'agit d'API 3D

  8. #8
    Membre chevronné
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 366
    Par défaut
    Citation Envoyé par Kaktus
    . J'ai pas trouvé de moyen efficace d'appliquer des textures (soit trop grande, et en dynamique c'est vraiment lent
    Si tu utilises des shaders, tu peux "sans pertes de perfo" (on presque) en dynamique appliquer plusieurs textures par vertex en utilisant :

    - x , y pour connaitre les coordonnes sur les textures
    - z pour connaitre les proportions de chaque textures

  9. #9
    Membre chevronné
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 366
    Par défaut
    Citation Envoyé par Kaktus

    IL ne me reste plus qu'à précalculer les normales.
    Note qu en utilisant des vertex shader 3.0 (rien que ca) tu peux utiliser une texture pour connaitre l elevation de chaque point du terrain.
    Avec un rendu sur texture, et un shader approprie, la premiere texture peut te permettre de generer une texture contenant les normales

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. OpenGL et threads
    Par CliffeCSTL dans le forum Multithreading
    Réponses: 1
    Dernier message: 28/03/2013, 10h53
  2. Rendu opengl multi-thread
    Par mick22 dans le forum Android
    Réponses: 4
    Dernier message: 26/02/2009, 16h21
  3. opengl et thread
    Par clemt dans le forum OpenGL
    Réponses: 14
    Dernier message: 11/07/2007, 15h05
  4. Rendu OpenGL sur un thread tier.
    Par Groove dans le forum OpenGL
    Réponses: 3
    Dernier message: 15/02/2007, 11h36
  5. boost::thread et OpenGL
    Par Kurisu dans le forum Boost
    Réponses: 12
    Dernier message: 19/09/2006, 13h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo