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

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

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.