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 :

Terrain très large


Sujet :

OpenGL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  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 Terrain très large
    Bonjour,

    Voilà je souhaite générer un terrain très large (pour qu'on puisse se balader dessus ).

    J'arrive en gros à générer un terrain 1048*1048 sans que ça rame après plusieurs problèmes se posent :

    - la taille en mémoire (déjà c conséquent là)
    - ca ralentit si c'est trop large (normal)
    - j'ai remarqué qu'utiliser une grande texture sur une grande map posaient bcp de difficultés niveau mémoire. En effet générer le million de hauteurs de la map + les 4 millions de la texture ne passe pas niveau mémoire. J'ai contourné le problème en faisant le mixage des couleurs au niveau de la liste e qui donne un résultat très proche.

    Voici le code (si ç a peut servir à qqun)



    * les classes :

    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
     
    struct Dimension
    {
    	 // Données membres
    	std::vector<float> heights;
    	int size;
     
    	 // Constructeur
    	Dimension(int sz=0) : size(sz) {}
     
    	 // Fonctions membres d'initialisation
    	void init();				// Initialise heights à zéro
    	void initRandom(int,int);   // Donne des valeurs aléatoires à heights entre deux bornes	
     
    	std :: vector<float> & get();		// Renvoi un alias de heights;
    	const std :: vector<float> & get() const;
    };

    /***********************************************************/

    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
    // On regroupe les données statiques de la map
     
    struct DataMap
    {
    	static const int MAX_HEIGHT = 30;
    	static const int MIN_HEIGHT = -20;
    	static const int OCTAVES = 6;
    	static const float INIT_PERSISTENCE = 0.5;
    	static const int INIT_FREQUENCY = 2;
    	static const int LINEARITY = 2;
    };
     
     
    	/***********************************************************************************/
     
     
    struct Map 
    {
    	 // Données membres
    	Dimension dimension;	
    	GLuint map_list;
     
     
    	 // Constructeur
    	Map(int sz) : dimension(Dimension(sz)) {}
    	~Map();
     
     
    	 // Fonctions membres
    	void prepareMap();
    	void create();
    	void draw() const;
    };



    Les deux fonctions-membres intéressantes :

    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
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
     
    void Map :: prepareMap()
    {
    	this->map_list = glGenLists(1);
     
    	Ptr<SDL_Surface> grass = IMG_Load("Images/Grass.jpg");	// Surface sdl	
    	Ptr<SDL_Surface> rock = IMG_Load("Images/Rock.jpg");
     
    	glNewList(this->map_list,GL_COMPILE);					// Génération du handle de la display list de la map
     
    	int map_size = dimension.size;
     
    	float lowlands = (float)(0.33*(DataMap :: MIN_HEIGHT +  DataMap :: MAX_HEIGHT));
    	float midlands = (float)(0.5*(lowlands + DataMap :: MAX_HEIGHT)); 
    	float highlands = (float)(0.5*(midlands + DataMap :: MAX_HEIGHT));
     
    	SDL_WM_SetCaption("Préparation de la texture",0); 
     
    	for(int z=0; z<map_size-1; ++z)
    	{
    		glBegin(GL_TRIANGLE_STRIP);
    		for (int x=0; x<map_size; ++x)
    		{
    			float scaled_height = this->dimension.heights[z*map_size + x];	// Hauteur de la map en (x/z)
    			float nextz_scaled_height = this->dimension.heights[(z+1)*map_size + x]; // en x/z+1
     
    			// Récupération des couleurs de l'herbe et rock au point (x/y/z et x/y/z+1)
    			SDL_Color grass_col = grass.getPixel(x%grass.getWidth(),z%grass.getHeight());
    			SDL_Color rock_col = rock.getPixel(x%rock.getWidth(),z%rock.getHeight());
     
    			SDL_Color nextz_grass_col = grass.getPixel(x%grass.getWidth(),(z+1)%grass.getHeight());
    			SDL_Color nextz_rock_col = rock.getPixel(x%rock.getWidth(),(z+1)%rock.getHeight());
     
    			// Création de la future couleur en fonction de la hauteur de la map et de celle de l'herbe + du rock
    			SDL_Color scaled_col, nextz_scaled_col;
    			if (scaled_height <= lowlands )		// plaine
    			{
    				scaled_col.r = grass_col.r;
    				scaled_col.g = grass_col.g;
    				scaled_col.b = grass_col.b;
    			}
     
    			else if (scaled_height <= midlands ) // Faible altitude
    			{
    				scaled_col.r = static_cast<int>(scaled_height/highlands*rock_col.r + 
    					(1-scaled_height/highlands)*grass_col.r);
    			 	scaled_col.g = static_cast<int>(scaled_height/highlands*rock_col.g + 
    				 	(1-scaled_height/highlands)*grass_col.g);
    			 	scaled_col.b = static_cast<int>(scaled_height/highlands*rock_col.b + 
    				 	(1-scaled_height/highlands)*grass_col.b);
    			} 
    			else  								// Moyenne altitude
    			{
    				scaled_col.r = rock_col.r;
    				scaled_col.g = rock_col.g;
    				scaled_col.b = rock_col.b;
    			}
     
    			// Maintenant pour le deuxième point (x/y/z+1)
    			if (nextz_scaled_height <= lowlands )
    			{
    				nextz_scaled_col.r = nextz_grass_col.r;
    				nextz_scaled_col.g = nextz_grass_col.g;
    				nextz_scaled_col.b = nextz_grass_col.b;
    			}
     
    			else if (nextz_scaled_height <= midlands )
    			{
    				nextz_scaled_col.r = static_cast<int>(nextz_scaled_height/highlands*nextz_rock_col.r + 
    					(1-nextz_scaled_height/highlands)*nextz_grass_col.r);
    			 	nextz_scaled_col.g = static_cast<int>(nextz_scaled_height/highlands*nextz_rock_col.g + 
    				 	(1-nextz_scaled_height/highlands)*nextz_grass_col.g);
    			 	nextz_scaled_col.b = static_cast<int>(nextz_scaled_height/highlands*nextz_rock_col.b + 
    				 	(1-nextz_scaled_height/highlands)*nextz_grass_col.b);
    			} 
    			else  
    			{
    				nextz_scaled_col.r = nextz_rock_col.r;
    				nextz_scaled_col.g = nextz_rock_col.g;
    				nextz_scaled_col.b = nextz_rock_col.b;
    			}
     
    			 // On trace les vertices + couleurs
    			glColor3ub(scaled_col.r,scaled_col.g,scaled_col.b);
    			glVertex3f( 0.5*(float)(x-map_size/2),scaled_height,0.5*(float)(z-map_size/2) );
     
    			glColor3ub(nextz_scaled_col.r,nextz_scaled_col.g,nextz_scaled_col.b);	
    			glVertex3f( 0.5*(float)(x-map_size/2),nextz_scaled_height,0.5*(float)(z+1-map_size/2));				
    		}
    		glEnd();
    	}
     
    	glEndList();
    }			
     
     
     // Dessin de la map
    void Map :: draw() const
    {
    	glDisable(GL_TEXTURE_2D);	// Sert à rien ici
    	glCallList(this->map_list);	
    	glEnable(GL_TEXTURE_2D);	 // On le remet
    }



    - Les hauteurs de la map sont précalculées et stockés dans un vector de taille map_size*map_size en float. (dans heights)
    - grass et rock sont -comme vous l'aurez compris- mes textures de taille modeste (genre 400*400).
    - j'ai multiplie les vertex par 0.5, surtout pour un souci de netteté (mais je perd en taille).


    UN GRAND MERCI POUR LES AUTEURS DE L'ALGO DE PERLIN, ca marche NICKEL.



    Maintenant je voudrais savoir comment je peux générer une map plus grande sans trop manger niveau ram (là 200 Mo pour le prog ).

    Deux idées pour l'instant :
    - Faire comme sur Everquest (ah, le bon vieux temps) , des zones de recharges (bon c'est faisable ) aux extrémités des maps mais c'est bof en jouabilité surtout si on fait des allers-retours.
    - Faire comme les jeux plus modernes, un chargement en continu mais là j'ai aucune idée simple (à part des requêtes sql pour récup des coordonnées ou sur fichier XML () et faire varier mes boucles for en fonction de ça ???


    Je suis ouvert à toute idée :p.

  2. #2
    Membre éprouvé Avatar de razmott
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 133
    Par défaut
    Salut !

    Tu pourrais peut-être diviser ta carte en plusieurs plus petites. Afin de faire du chargement continu, effectue-le dans une autre thread.
    Maintenant avec du frustum culling tu devrais pouvoir isoler les seules petites cartes visibles et limiter l'utilisation de la mémoire.

    @+

  3. #3
    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
    le mieux a mon avis pour ce genre de probleme , c'est

    -utiliser des vertex shader 3.0 (qui permettent , si ta carte graphique le permet d'utiliser un texture memoire pour representer une elevation)

    -en utilisant plusieurs textures, tu peux alors mettre en commun les coordonnes x y des vertex (tu creer et vertex buffer qui dessine simplement u n cadrillage 2D = damier) et ton shader permet de deduire la coordonnees z par rapport a ta texture.

    En utilisant le meme vertex buffer , mais plusieurs textures d'altitudes tu peux des plusieurs damiers, et en les collant tu arrives a avoir de grands terrains (bien plus que 1024x1024 ...*)

    -ensuite il faut que le moteur soit capable de charger des textures a la volee (donc multithreading) et la ca se complique


    Ton probleme est loin d etre semble, cela dit en passant:

    * : Tu veux faire des terrains immenses sans que ca rame, donc il faut donc gerer du Level Of Detail et donc que les "damiers" les plus eloignes de la camera aient une resolution moindre . Coller deux damiers de resolutions differentes sans artefacts graphiques est un probleme qui n est pas trivial (il existe pleins d articles la dessus --> mot cle "geomorphisme".

    note : je ne suis pas sur que la list opengl soit aussi efficace que le les vertex / index buffer.

    note : l utilisation de shader permet aussi d'eviter d ajoueter des coordonnees de textures aux vertices (on peut les deduire a partir de x et y).
    Les shader permettent aussi de faire du multitexturing par altitude (la , je peux t envoyer des exemples rendermonkey si ca t interresse)
    Images attachées Images attachées  

  4. #4
    Membre très actif
    Profil pro
    Responsable technique
    Inscrit en
    Février 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Responsable technique

    Informations forums :
    Inscription : Février 2006
    Messages : 366
    Par défaut
    Regarde du coté du code source de Delta3D. C'est un moteur 3D open source basé sur OpenSceneGraph et qui gere le LOD et les map enorme à partir de fichier images en niveau de gris notamment. Je l'utilise en ce moment et j'ai affiché la france. Voila le lien du site:
    http://www.delta3d.org/

    J'espere que ca pourra te donner des idées de regarder ce qui a été fait.

  5. #5
    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
    Pareil pour ogre qui possede un plugin 'PagingLandscape' qui permet de faire du LOD + chargement de bloc a la volee (mais je ne crois pas en multithread)

  6. #6
    Membre très actif
    Profil pro
    Responsable technique
    Inscrit en
    Février 2006
    Messages
    366
    Détails du profil
    Informations personnelles :
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Responsable technique

    Informations forums :
    Inscription : Février 2006
    Messages : 366
    Par défaut
    Citation Envoyé par smashy
    Pareil pour ogre qui possede un plugin 'PagingLandscape' qui permet de faire du LOD + chargement de bloc a la volee (mais je ne crois pas en multithread)
    Oué mais j'ai testé les 2 et Delta3D est bien plus evolué que le plugin de Ogre.

  7. #7
    Membre Expert
    Avatar de shenron666
    Homme Profil pro
    avancé
    Inscrit en
    Avril 2005
    Messages
    2 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : avancé

    Informations forums :
    Inscription : Avril 2005
    Messages : 2 580
    Par défaut
    Citation Envoyé par smashy
    le mieux a mon avis pour ce genre de probleme , c'est

    -utiliser des vertex shader 3.0 (qui permettent , si ta carte graphique le permet d'utiliser un texture memoire pour representer une elevation)
    ça c'est pas une solution, plutot de l'optimisation et encore faut-il avoir une carte graphique qui gère les shaders 3.0

    il faut surtout, comme le dit razmott, gérer une grande map en plusieurs petites mises bout à bout, gérer le frustum culling et éventuellement faire du LOD (+ pour la fluidité mais potentiellement - pour la consommation mémoire selon la technique utilisée)

    le site vterrain.org regroupe de nombreux liens pour tout ce qui concerne les terrains virtuels
    bon courage
    Tutoriels OpenGL
    Je ne répondrai à aucune question en MP
    - Si c'est simple tu dis que c'est compliqué et tu le fait
    - Si c'est compliqué tu dis que c'est simple et tu le sous-traite ou le fait faire par un stagiaire.

  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
    certes, le gros du probleme , c'est d etre capable de :

    - charger le terrain au fur et a mesure

    - etre capable d'afficher du LOD

    - faire du frustum culling

    L avantage d'utiliser du vertex shader 3 (encore faut il que la carte le supporte --> post nvidia 6600), c'est de limiter la bande passante disque dur (puisque l on est affranchie des composantes x et y) et la bande passante CPU-GPU (pour les meme raison).

    De surcroix l utilisation de texture permet d'avoir a faire a la main des vertex et indexes buffer pour chaque LOD puisque ce sont des resources partagees entre chaques patch de terrains.... la encore on y gagne en calcul. Enfin l'utilisation d un shader permet de faire du progressive LOD pour un cout presque nul.

    Donc effectivement, quand je parle de vertex shader 3 c'est effectivement de l'optimisation, mais si la problematique est bien de rendre des terrains immenses sans que ca rame alors c'est pas tout a fait hors sujet

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

Discussions similaires

  1. div très large sous div flottant à droite
    Par Aquellito dans le forum Mise en page CSS
    Réponses: 13
    Dernier message: 07/04/2011, 19h26
  2. rich:calendar dans ie8 s'affiche très large
    Par JAMINF dans le forum JSF
    Réponses: 3
    Dernier message: 12/05/2010, 16h47
  3. Tableau très large
    Par wafer dans le forum Tableaux - Graphiques - Images - Flottants
    Réponses: 5
    Dernier message: 17/03/2010, 14h51
  4. Agrandir un DIV lorsqu'une page est très large
    Par Poulpynette dans le forum Mise en page CSS
    Réponses: 12
    Dernier message: 27/03/2009, 14h45
  5. [HTML 4.0] Fixer une largeur de colonne dans une table très large
    Par Poulpynette dans le forum Balisage (X)HTML et validation W3C
    Réponses: 12
    Dernier message: 11/03/2009, 11h02

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