Landscape gl : génération de paysage en 3d

Soyez le premier à donner votre avis sur cette source.

Vue 6 024 fois - Téléchargée 417 fois

Description

Cette source est basée sur un article du magazine Login n 107
Elle genere un paysage en 3D et l'affiche grace a openGL en mode fil de fer (voir la catpure).
On peut changer la taille du paysage ainsi qu'un parametre permettant d'avoir un paysage plus ou moins lisse.
Il y a inclus dans le zip une explication de 11 pages du procédé de génération du paysage(en .doc plus facile pour les schemas) .Si avec ça vous ne comprenez pas c'est que je ne sais vraiment pas bien expliquer.

Touches utiles (par defaut prevu pour un QWERTY)
W pour se deplacer en avant
S en arriere
A a gauche
D a droite
Les fleches directionnelles pour modifier la vue (tourner a gauche a droite en haut et en bas)
Et enfin R qui recalcule un nouveau paysage

Pour une taille de paysage de 9 ou plus l'affichage (pas le calcul) est assez saccadé.(taille de 9 = paysage de plus de 130 000 triangles)

Si vous ne voulez pas Dl le zip ou pour la compil codes-sources il y a le code en bas qui est modifié pour ne pas avoir de boite de configuration au demarrage (changement des params direct dans le code)

Je ne sais pas trop dans quelle catégorie le mettre je ne le met pas dans openGl car ici il sert juste a l'affichage et l'important est quand même la génération du terrain.

Source / Exemple :


/*-----------------------------------------------------------------------------------------------*
//
//                                      LandscapeGL
//
//Fait par         : MaegisInstinct (maegisinstinct@free.fr)
//
//le               : 14/08/2003 à 13:03:45
//
//Description      : Generation d'un paysage
//
//Note			   : Lire le fichier readme.doc pour avoir une explication de le methode de 
//					 generation du terrain et de l'affichage
//
/*----------------------------------------------------------------------------------------------*/

//Includes 
#include <windows.h>
#include <stdlib.h>		//rand
#include <gl/gl.h>
#include <gl/glu.h>

#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")

//Declarations
void				Draw(HDC,double **,int,int,int,int,int,int);				//fonction de dessin
void				Reshape(int,int);
void				SetupPixelFormat(HDC);
double**			CalculLand(int,double);					//Generation du terrain
double**			CreateTableau2d(int);					//Cree un tableau a 2 dimensions
void				DeleteTableau2d(double **,int);			//Delete le tableau
void				SquareStep(double**,int,int,double);	//Etape de creation du terrain
void				DiamondStep(double**,int,int,double,int);	//2 etape de creation du terrain
LRESULT CALLBACK	WinProc(HWND,UINT,WPARAM,LPARAM);	

//Var globales
int		pow2[15]		= {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};	//puissances de 2
double	lisse			= 2;
int		tailletableau	= 8;

//--------------
//Fonction main
//--------------
int APIENTRY WINAPI WinMain(HINSTANCE hInstance,  
							HINSTANCE hPrevInstance,   
							LPSTR lpCmdLine,   
							int nCmdShow)
{
	MSG			msg;
	WNDCLASS	wc;
	HWND		hWnd;

	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hbrBackground	= (HBRUSH) GetStockObject(BLACK_BRUSH);
	wc.hCursor			= NULL;
	wc.hIcon			= NULL;
	wc.hInstance		= hInstance;
	wc.lpfnWndProc		= &WinProc;
	wc.lpszClassName	= "Fenetre GL";
	wc.lpszMenuName		= NULL;
	wc.style			= CS_HREDRAW | CS_VREDRAW;

	RegisterClass(&wc); 

	//on cree la fenetre
	hWnd = CreateWindow("Fenetre GL",
                        "Landscape",
                         WS_POPUP,
                         0,0,
                         GetSystemMetrics(SM_CXSCREEN),
                         GetSystemMetrics(SM_CYSCREEN),
                         NULL,
					     NULL,
                         hInstance,
                         NULL);

	ShowWindow(hWnd,SW_SHOW);
	UpdateWindow(hWnd);
	ShowCursor(FALSE);		//on cache le curseur

	 while (GetMessage(&msg,NULL,0,0))
	 {
		 TranslateMessage(&msg);
		 DispatchMessage(&msg);
	 }

	return msg.wParam;
}

//----------------------------------------------------
//Met l'affichage en 32bits et specifie le backbuffer
//----------------------------------------------------
void SetupPixelFormat(HDC hDC)
{
	int pixelFormat;
    PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),
		1,
        PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER,
        PFD_TYPE_RGBA,
        32,
        0, 0, 0, 0, 0, 0,
        0, 0,	
        0, 0, 0, 0, 0,
        32,
        0,
        0,
        0,
        0,
        0,
        0,
        0
	};

    pixelFormat = ChoosePixelFormat(hDC, &pfd);
    if (pixelFormat == 0)
	{
        MessageBox(NULL,"Mode graphique non supporté","Erreur",MB_OK);
        exit(1);
    }

    if (SetPixelFormat(hDC,pixelFormat,&pfd) != TRUE)
	{
		MessageBox(NULL,"Mode graphique non supporté","Erreur",MB_OK);
        exit(1);
    }
}

//---------------------------------
//Fonction de gestion des messages
//---------------------------------
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	HDC				hdc;
	PAINTSTRUCT		ps;
	static HGLRC	hrc;
	static double**	tableau			= NULL;
	//Variables pour le deplacement sur le terrain
	static int		anglex			= 0;
	static int		angley			= 0;
	static int		distance		= 25;
	static int		strafe			= 0;
	static int		hauteur			= 0;

	switch(msg)
	{
	case WM_CREATE:

		srand(GetTickCount());						//on initialise rand
		tableau = CalculLand(tailletableau,lisse);	//on genere le terrain

		if (tableau == NULL)
		{
			MessageBox(hWnd,"Erreur d'allocution de memoire","Erreur de memoire",MB_OK | MB_ICONEXCLAMATION);
			PostQuitMessage(0);
		}

		hdc=GetDC(hWnd);
		SetupPixelFormat(hdc); //on set le mode d'affichage
		hrc = wglCreateContext(hdc);		//On cree un rendering context
		if (!hrc)
			DestroyWindow(hWnd);
		wglMakeCurrent(hdc,hrc);		//on l'associe au DC
		break;

	case WM_DESTROY:

		wglMakeCurrent(NULL,NULL);		//on libere le RC
		if (hrc)
			wglDeleteContext(hrc);		//on le delete
		if (tableau != NULL)
			DeleteTableau2d(tableau,pow2[tailletableau]+1);		//on libere la memoire
		PostQuitMessage(0);
		break;

	case WM_SIZE:

		Reshape(LOWORD(lParam),HIWORD(lParam));		//on met a jour l'affichage
		break;

	case WM_KEYDOWN :
		InvalidateRect(hWnd,NULL,FALSE);		//on redessinne
		switch(wParam)
		{

		case VK_ESCAPE :
			DestroyWindow(hWnd);
			break;

		case 'R' :
			DeleteTableau2d(tableau,tailletableau);		//on delete le tableau
			tableau = CalculLand(tailletableau,lisse);			//on recalcule
			InvalidateRect(hWnd,NULL,FALSE);
			break;

//gestion du deplacement
		case VK_LEFT :
			angley++;
			break;
		case VK_RIGHT :
			angley--;
			break;
		case VK_UP :
			anglex++;
			break;
		case VK_DOWN :
			anglex--;
			break;
		case 'W' :
			distance--;
			break;
		case 'S' :
			distance++;
			break;
		case 'A' :
			strafe++;
			break;
		case 'D' :
			strafe--;
			break;
		case 'C' :
			hauteur--;
			break;
		case VK_SPACE :
			hauteur++;
			break;
		}
		break;
	case WM_PAINT:

		if (tableau != NULL)
		{
			hdc = BeginPaint(hWnd,&ps);
			Draw(hdc,tableau,pow2[tailletableau],anglex,angley,distance,strafe,hauteur);  //on Draw la scene
			EndPaint(hWnd,&ps);
		}
		break;
	}

	return DefWindowProc(hWnd,msg,wParam,lParam);
}

//-------------------
//Fonction de dessin
//-------------------
void Draw(HDC hdc,double **tableau,int indexmax,int anglex,int angley,int distance,int strafe,int hauteur)
{
	int i,j;

	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		//on efface tout
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity(); 
	gluLookAt(0,0,25,0,0,0,0,1,0);				//on defini le point de vue
	glPushMatrix();	

//Gestion du deplacement
	glTranslated(strafe,-hauteur,-distance);
	glRotated(anglex,1,0,0);
	glRotated(-angley,0,1,0);
	

	glScaled(50.0/indexmax,50.0/indexmax,50.0/indexmax); //mise a l'echelle
	

//affichage
		for(i=0;i<indexmax;i++)
		{
			for(j=0;j<indexmax;j++)
			{
				glBegin(GL_LINE_LOOP);
				glVertex3i(i+1-indexmax/2	,(int)tableau[i+1][j]	,j-indexmax/2	);
				glVertex3i(i-indexmax/2		,(int)tableau[i][j]		,j-indexmax/2	);
				glVertex3i(i-indexmax/2		,(int)tableau[i][j+1]	,j+1-indexmax/2	);
				glVertex3i(i+1-indexmax/2	,(int)tableau[i+1][j]	,j-indexmax/2	);
				glVertex3i(i+1-indexmax/2	,(int)tableau[i+1][j+1]	,j+1-indexmax/2	);
				glVertex3i(i-indexmax/2		,(int)tableau[i][j+1]	,j+1-indexmax/2	);
				glEnd();
			}
		}

	glPopMatrix();
	SwapBuffers(hdc);
}

//---------------------------------------------------------
//Cree le landscape (retourne un pointeur vers le tableau)
//---------------------------------------------------------
double** CalculLand(int taille,double lisse)
{
//Pour l'explication lire le readme !

	double**	tableau;
	int			indexmax = pow2[taille];
	int			step;
	int			i;
	double		randRange = indexmax/2.0;

	if (lisse > 10)		//lisse compris entre 1.5 (horriblement escarpé)
		lisse = 10;		//et 10 (pas mal lisse)
	if (lisse <1.5)
		lisse = 1.5;
	
	if (taille < 1 )	//on verifie que la taille ne soit pas trop grande (affichage tres long)
		taille = 1;		//et qu'elle soit au moins de 1
	if (taille > 11 )
		taille = 11;

	tableau = CreateTableau2d(indexmax+1);		//Creation du tableau

	if(tableau == NULL)
		return tableau;

	//initialisation des 4 coins du tableau (on peut mettre une autre valeur)
	tableau[0][0]				= 0;
	tableau[0][indexmax]		= 0;
	tableau[indexmax][indexmax] = 0;
	tableau[indexmax][0]		= 0;

	step = indexmax;

	for(i = 0;i<taille;i++)		//on genere le terrain
	{	
		SquareStep(tableau,i,step,randRange);
		DiamondStep(tableau,i,step,randRange,indexmax);

		if (randRange > 1)
			randRange /= lisse; 
		if (randRange < 1)  //pour eviter le x%0 qui n'existe pas
			randRange = 1;

		step /= 2;
	}

	return tableau;
}

//---------------------------------------
//1ere etape de generation (voir readme)
//---------------------------------------
void SquareStep(double **tableau,int nb_passes,int step,double randRange)
{
	int debI,midI,finI;
	int debJ,midJ,finJ;
	int i,j;

	debI =	0;
	midI = step/2;
	finI = step;

	for(i=0;i<pow2[nb_passes];i++)
	{
		debJ = 0;			//on revient a 0 pour une autre boucle
		midJ = step/2;
		finJ = step;

		for(j=0;j<pow2[nb_passes];j++)
		{
//On fait la moyenne des cases avoisinantes + un nombre compris en -randRange et +randRange
			tableau[midI][midJ] = (tableau[debI][debJ] + tableau[debI][finJ] + tableau[finI][finJ] + tableau[finI][debJ] ) /4.0 + (rand()%((int)randRange*2))-randRange;

			debJ += step;		//on incremente
			midJ += step;
			finJ += step;
		}

		debI += step;		//incrementation
		midI += step;
		finI += step;
	}
}

//-----------
//2eme etape
//-----------
void DiamondStep(double **tableau,int nb_passes,int step,double randRange,int indexmax)
{
	int debI,midI,finI;
	int debJ,midJ,finJ;
	int i,j;
	int halfstep = step/2;		//pour eviter les step/2 tout le temps
	
	midI = 0;
	debI = indexmax-halfstep;
	finI = halfstep;

	for(i=0;i<pow2[nb_passes+1];i++)
	{
		if(i%2)
		{
			midJ = 0;
			debJ = indexmax-halfstep;
			finJ = halfstep;
		}
		else
		{
			midJ = halfstep;
			debJ = 0;
			finJ = step;
		}

		for(j=0;j<pow2[nb_passes];j++)
		{
			//Moyenne + nombre entre -randRange et +randRange
			tableau[midI][midJ] = (tableau[midI][debJ] + tableau[midI][finJ] + tableau[debI][midJ] + tableau[finI][midJ]) /4.0 + (rand()%((int)randRange*2))-randRange;

			debJ = (debJ+step)%indexmax;		//explication dans le readme
			midJ += step;
			finJ += step;
		}

		debI = (debI+halfstep) % indexmax;
		midI += halfstep;
		finI += halfstep;
	}

	//Recopiage des extremites
	midI = halfstep;
	for(i=0;i<pow2[nb_passes];i++)
	{
		tableau[indexmax][midI] = tableau[0][midI];
		tableau[midI][indexmax] = tableau[midI][0];
		midI += step;
	}

}

//-------------------------------
//Cree un tableau a 2 dimensions
//-------------------------------
double** CreateTableau2d(int taille)
{
	double** tableau;
	int i;

	tableau = new double*[taille];
	if(tableau != NULL)
	{
		for(i=0;i<taille;i++)
		{
			tableau[i] = new double[taille];

			if (tableau[i] == NULL)		//si erreur on delete
			{
				DeleteTableau2d(tableau,taille);
				return NULL;				
			}

		}
	}
	return tableau;
}

//---------------------------------
//Delete le tableau a 2 dimensions
//---------------------------------
void DeleteTableau2d(double **tableau,int taille)
{
	int i;

	for(i=0;i<taille;i++)
	{
		if (tableau[i] != NULL)		//on verifie que le pointeur ne soit pas null
			delete[] tableau[i];
	}

	delete[] tableau;
}

//-------------------------------------------------------
//Definition de la perspective et de la zone d'affichage
//-------------------------------------------------------
void Reshape(int width,int height)
{
	glViewport(0,0,width,height);	//on defini la taille
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0,(GLdouble) width/height,0,500);
}

Conclusion :


Je trouve que l'algo de génération n'est pas évident du premier coup mais allez vois dans le zip lire le readme et vous devriez comprendre.
Je suis pas super fort pour expliquer alors dites moi si vous trouvez l'explication peu claire

Je ne suis pas tres fort en openGL , surtout gestion des lumieres car je voulais faire une version en affichage par exemple tout en blanc et avec les lumieres ça aurait rendu quelque chose mais sans ...
En fait j'arrive a mettre les lumieres mais elles n'eclairent pas comme je le veux. Si quelqu'un peut m'aider..

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

KoniKoni88
Messages postés
1
Date d'inscription
mercredi 26 mai 2010
Statut
Membre
Dernière intervention
6 février 2011
-
Salut,

J'ai pas mal étudié ton programme, et j'ai aussi un problème pour "colorier" le paysage montagneux. En fait j'utilise une fonction pour que la couleur varie avec l'altitude mais je n'arrive pas à obtenir une texture ...
DedeSurf
Messages postés
159
Date d'inscription
mardi 17 décembre 2002
Statut
Membre
Dernière intervention
23 novembre 2011
-
Salut,
Il faut dire que sa vaut le coup d'oeil
je mettrai 8/10 a 9/10, j'y réfflaichirais !
Thyraël
Maegis
Messages postés
101
Date d'inscription
vendredi 15 février 2002
Statut
Membre
Dernière intervention
6 août 2007
-
kidpigeyre je t'ai envoyé la réponse en MP
kidpigeyre
Messages postés
96
Date d'inscription
mardi 3 juillet 2001
Statut
Membre
Dernière intervention
2 novembre 2006
-
Bonjour,

J'ai longuement regardé ton programme car je dois réaliser un logiciel de modélisation et statistiques en un ensemble de montagne 3D.

Cependant, lors de l'éxécution de ton programme, je trouve un problème d'affichage. En effet certain point lors d'une rotation par les fleches de mouvements ne sont plus reliés par des filaments, on ne les voit plus, ainsi lorsque j'ai essayé d'y rajouter les textures, j'ai des plaques noires ou il y a rien.

Je n'ai aps bien compris ton système pour dessiner les vecteurs dans la fonction draw.

Tu pourrais me l'expliquer? Jpense que ça vient d'ici mais je ne suis pas sur.

Mci.

Romain
houmiak
Messages postés
44
Date d'inscription
mercredi 18 juin 2003
Statut
Membre
Dernière intervention
27 août 2003
-
en groupant tes donnée localement, tu as de grandes chances de retrouver dans ton cache la donnée que tu vas utiliser au prochain step de ton prog (les ram et les caches L2 des CPU transfèrent souvent des bloc, pas une donnée) donc avec un tel tableau (a condition de le parcourir inteligemment), ce que tu perd en multiplication, tu le gagne largement en latence mémoire.
de plus, si tu commence a envisager des calcul vectoriel, une telle organisation est indispensable pour de bonnes performances.
a bientot ;o)

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.