Moteur 3d dimetrique

Soyez le premier à donner votre avis sur cette source.

Vue 13 183 fois - Téléchargée 1 123 fois

Description

c'est une application qui affiche un terrain en projection orthogonale dimetrique. une projection dimétrique est une projection gardant les projections de 2 axes (une projection isometrique garde les proportions des 3 axes) . cette projection est faite à l'aide d'une matrice de transformation Opengl

la projection permet de changer l'inclinaison du terrain et de le faire tourner mais je n'ai pas implementer de depth sorting et en regardant le terrain de l'arriere on voit les faces avant .

->click gauche sur l'eau : crée des vagues
-> drag click droit : scroll (translate) le terrain
-> drag click milieu : change l'echelle (scale) le terrain
-> drag click gauche+droite : change l'inclinaison et la rotation du terrain

le programme tourne à 75fps sur mon ordinateur (Geforce 2 MX T_T): je pense qu'il n'est limité que par le nombre de polygones à affiché (128*128)

l'executable est trop gros pour le zip
mais vous pouvez le trouver sur http://matt2000.free.fr/release.rar ainsi que des textures non compressés

Source / Exemple :


void CTerrainNode::Draw() {

GLdouble model[16], proj[4][4];
GLint view[4];
glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);
glGetIntegerv(GL_VIEWPORT, &view[0]);
double x,y,z;
char tmp[32];
unsigned char white[] = { 255,255,255 },height;
short mx = WindowMaker->mouse.x;
short my = WindowMaker->mouse.y;

/**
Projection setting

    • /
glPushMatrix(); float matrix[16]= { sqrt(2)*0.5 , -sqrt(2)*0.5*sin((float)(256-View->camera.ry)/256) , 0 , 0, -sqrt(2)*0.5 , -sqrt(2)*0.5*sin((float)(256-View->camera.ry)/256) , 0 , 0, 0 , cos((256-View->camera.ry)/256) , 1 , 0, View->camera.x , View->camera.y , 0 , 1 }; glLoadMatrixf(matrix); glRotatef((-View->camera.rx+128)/2.8,0,0,1); glScalef((float)View->camera.zoom/8,(float)View->camera.zoom/8,(float)View->camera.zoom/16); /** Terrain rendering
    • /
glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glBindTexture( GL_TEXTURE_2D, tilemap->id ); for(int i=0;i<heightmap->height-1;i++) { for(int j=0;j<heightmap->width-1;j++) { glBegin(GL_QUADS); glTexCoord2f((float)i/heightmap->width,(float)j/heightmap->height); glVertex3f(i ,j ,heightmap->get(i,j,0)); glTexCoord2f((float)(i+1)/heightmap->width,(float)(j)/heightmap->height); glVertex3f(i+1 ,j ,heightmap->get(i+1,j,0)); glTexCoord2f((float)(i+1)/heightmap->width,(float)(j+1)/heightmap->height); glVertex3f(i+1 ,j+1 ,heightmap->get(i+1,j+1,0)); glTexCoord2f((float)(i)/heightmap->width,(float)(j+1)/heightmap->height); glVertex3f(i ,j+1 ,heightmap->get(i,j+1,0)); glEnd(); } } glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glDisable(GL_TEXTURE_2D); /** retrieve the mouse position on the terrain
    • /
glGetDoublev(GL_MODELVIEW_MATRIX, &model[0]); double right[3]; right[0] = model[0]; right[1] = model[4]; right[2] = model[8]; float w; glReadPixels(mx,768-my,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&w); //read pixel (GL_FLOAT) return a float not a double z = w; gluUnProject( mx,768-my,z,&model[0], &proj[0][0], &view[0], &x, &y,&z); ix = x+0; iy = y+0; if(ix>127) ix = 127; else if(ix<0) ix = 0; if(iy>127) iy = 127; else if(iy<0) iy = 0; glColor4ub(255,0,0,128); glBegin(GL_QUADS); glVertex3f(ix ,iy ,heightmap->get(ix,iy,0)); glVertex3f(ix+1 ,iy ,heightmap->get(ix+1,iy,0)); glVertex3f(ix+1 ,iy+1 ,heightmap->get(ix+1,iy+1,0)); glVertex3f(ix ,iy+1 ,heightmap->get(ix,iy+1,0)); glEnd(); /** Object (tree,building) rendering using point sprite extension
    • /
glPointSize((float)View->camera.zoom/4); glTexEnvf (GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); glEnable (GL_POINT_SPRITE); glEnable(GL_TEXTURE_2D); glColor3ub(255,255,255); for(int i=0;i<heightmap->height-1;i++) { for(int j=0;j<heightmap->width-1;j++) { if( objectmap->get(i,j,0) && objectmap->get(i,j,0) <= nofObject ) { glBindTexture( GL_TEXTURE_2D, object [ objectmap->get(i,j,0) ].id ); glBegin(GL_POINTS); glVertex3f(i+0.5,j+0.5,heightmap->get(i,j,0)); glEnd(); } } } glPointSize(16); glDisable (GL_POINT_SPRITE); glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glColor4ub(96,192,255,64); for(int i=0;i<heightmap->height-1;i++) { for(int j=0;j<heightmap->width-1;j++) { if(heightmap->get(i,j,0) < 64) { glBegin(GL_QUADS); //glTexCoord2f((float)i/heightmap->width,(float)j/heightmap->height); glVertex3f(i ,j ,64+((float)wavemap[(i+j*128)*2+swap]/32)); //glTexCoord2f((float)(i+1)/heightmap->width,(float)(j)/heightmap->height); glVertex3f(i-1 ,j ,64+((float)wavemap[(i-1+j*128)*2+swap]/32)); //glTexCoord2f((float)(i+1)/heightmap->width,(float)(j+1)/heightmap->height); glVertex3f(i-1 ,j-1 ,64+((float)wavemap[(i-1+(j-1)*128)*2+swap]/32)); //glTexCoord2f((float)(i)/heightmap->width,(float)(j+1)/heightmap->height); glVertex3f(i ,j-1 ,64+((float)wavemap[(i+(j-1)*128)*2+swap]/32)); glEnd(); } } } glDisable(GL_DEPTH_TEST); sprintf(tmp," x %i y %i z %0.0f",ix,iy,z); gl.DrawText2D(128,128,white,2.0f,0,tmp); glPopMatrix();

Conclusion :


Features :
-projection dimétrique d'un terrain heightmappé et texturé
-Loader de texture tga,bmp & jpg
-selection de la case sous la souris
-affichage d'objet(arbres,batiments) (utilise l'extension point_sprite )
-simulation de l'eau ( vague )

Todo :
-lorsque j'aurai un carte graphique correcte, j'utiliserai l'extension frame buffer object pour faire le reflet de l'eau et ne rerendre qu'une partie de l'écran lors des translations
-possibilité de creation de route
-possibilité de creer un batiment -> selection du batiment -> debut d'interface pour créer des bonhommes
-pathfinding
-un vrai jeu ?

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
46
Date d'inscription
vendredi 14 janvier 2005
Statut
Membre
Dernière intervention
31 juillet 2006

oui je fais un render to texture du terrain . je n'ai pas deja affiche le terrain dans un fichier externe
et comme cest un vue orthogonale quand je translate ou scale ca ne deforme pas le terrain donc pas besoin de le rendre a chaque frame

normalement tu peux compiler sans probleme sous window$
Messages postés
546
Date d'inscription
vendredi 13 février 2004
Statut
Membre
Dernière intervention
9 janvier 2008
1
"pour le probleme des VBOS cest que si je ne veux pas quadruples les vertices il faut que je fasse en 4fois
car un vertices peut participer a 4 cases donc 4 TexCoords differents, ma solution est de rendre quatres fois en decalant les cases a chaque fois "

Je sais pas moi, ca depend de ce que tu veux faire exactement...

"il ny a aucun multitexturing en fait je render mon terrain sur une texture (comme si je l'affichais a l'ecran)
comme ca je le render qu'une seul fois et je peux bouger sans le re render"

La j'ai un peu de mal a comprendre...tu fasi du render to texture?? Si c'est le cas le vois pas l'utilité, et je sais toujours pas si tu créé ta texture proceduralement ou si tu l'a deja dans un fichier externe.

Et la j'ai pas les moyens de compiler...
Messages postés
46
Date d'inscription
vendredi 14 janvier 2005
Statut
Membre
Dernière intervention
31 juillet 2006

tu n'est pas oblige d avoir linux j'utilise SDL donc tu devrais pouvoir compiler sans probleme

il ny a aucun multitexturing en fait je render mon terrain sur une texture (comme si je l'affichais a l'ecran)
comme ca je le render qu'une seul fois et je peux bouger sans le re render

pour le probleme des VBOS cest que si je ne veux pas quadruples les vertices il faut que je fasse en 4fois
car un vertices peut participer a 4 cases donc 4 TexCoords differents, ma solution est de rendre quatres fois en decalant les cases a chaque fois

peut-etre que avec un bout de code ce sera plus comprehensible :

#include "../../include/terrain.h"

void CTerrain::DrawTile() {
/**
0 0 Tile Updating
**/

glBindBufferARB( GL_ARRAY_BUFFER_ARB, VBOTileTexCoords );
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );
float* TexCoords = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY);
for(int i=0;i<map->height-1;i+=2) {
for(int j=0;j<map->width-1;j+=2) {

TexCoords[(i*map->width+j)*2] = float(tileUV[ map->get(i,j,1)*8+0 ])/tiletex->width; // 0 0 u
TexCoords[(i*map->width+j)*2+1] = float(tileUV[ map->get(i,j,1)*8+1 ])/tiletex->height; // 0 0 v

TexCoords[((i+1)*map->width+j)*2] = float(tileUV[ map->get(i,j,1)*8+2 ])/tiletex->width; // 1 0 u
TexCoords[((i+1)*map->width+j)*2+1] = float(tileUV[ map->get(i,j,1)*8+3 ])/tiletex->height; //1 0 v

TexCoords[((i+1)*map->width+j+1)*2] = float(tileUV[ map->get(i,j,1)*8+4 ])/tiletex->width; //1 1 u
TexCoords[((i+1)*map->width+j+1)*2+1] = float(tileUV[ map->get(i,j,1)*8+5 ])/tiletex->height; //1 1 v

TexCoords[(i*map->width+j+1)*2] = float(tileUV[ map->get(i,j,1)*8+6 ])/tiletex->width; //0 1 u
TexCoords[(i*map->width+j+1)*2+1] = float(tileUV[ map->get(i,j,1)*8+7 ])/tiletex->height; //0 1 v
}
}
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);

glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, VBOTileIndices); /// Use Tile Indices
unsigned short* Indices = (unsigned short*)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY);

//Tile is rendered upon Terrain : you can use transparent tile
int u = 0;
for(int i=0;i<map->height-1;i+=2) {
for(int j=0;j<map->width-1;j+=2) {
if( map->get(i,j,1) && map->get(i,j,1) < nofObject ) { //if valid object render
Indices[u] = i*map->width+j; // 0 0
Indices[u+1] = (i+1)*map->width+j; // 1 0
Indices[u+2] = (i+1)*map->width+j+1; // 1 1
Indices[u+3] = (i)*map->width+j+1; // 0 1
u+=4;
}
}
}
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);

glBindBufferARB( GL_ARRAY_BUFFER_ARB, VBOVertices ); /// Keep Terrain Vertices
glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );


/**
Tile rendering
**/
glDisable(GL_DEPTH_TEST); //always render upon
glEnable(GL_TEXTURE_2D);
glDisable(GL_BLEND);

glColor3ub(255,255,255);
glBindTexture(GL_TEXTURE_2D,tiletex->id);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawElements(GL_QUADS, u, GL_UNSIGNED_SHORT, 0);

/**
1 0 Tile Updating
**/
glBindBufferARB( GL_ARRAY_BUFFER_ARB, VBOTileTexCoords );
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );
TexCoords = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY);

for(int i=1;i<map->height-1;i+=2) {
for(int j=0;j<map->width-1;j+=2) {

TexCoords[(i*map->width+j)*2] = float(tileUV[ map->get(i,j,1)*8+0 ])/tiletex->width; // 0 0 u
TexCoords[(i*map->width+j)*2+1] = float(tileUV[ map->get(i,j,1)*8+1 ])/tiletex->height; // 0 0 v

TexCoords[((i+1)*map->width+j)*2] = float(tileUV[ map->get(i,j,1)*8+2 ])/tiletex->width; // 1 0 u
TexCoords[((i+1)*map->width+j)*2+1] = float(tileUV[ map->get(i,j,1)*8+3 ])/tiletex->height; //1 0 v

TexCoords[((i+1)*map->width+j+1)*2] = float(tileUV[ map->get(i,j,1)*8+4 ])/tiletex->width; //1 1 u
TexCoords[((i+1)*map->width+j+1)*2+1] = float(tileUV[ map->get(i,j,1)*8+5 ])/tiletex->height; //1 1 v

TexCoords[(i*map->width+j+1)*2] = float(tileUV[ map->get(i,j,1)*8+6 ])/tiletex->width; //0 1 u
TexCoords[(i*map->width+j+1)*2+1] = float(tileUV[ map->get(i,j,1)*8+7 ])/tiletex->height; //0 1 v
}
}
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);

glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, VBOTileIndices); /// Use Tile Indices
Indices = (unsigned short*)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY);

//Tile is rendered upon Terrain : you can use transparent tile
u = 0;
for(int i=1;i<map->height-1;i+=2) {
for(int j=0;j<map->width-1;j+=2) {
if( map->get(i,j,1) && map->get(i,j,1) < nofObject ) { //if valid object render
Indices[u] = i*map->width+j; // 0 0
Indices[u+1] = (i+1)*map->width+j; // 1 0
Indices[u+2] = (i+1)*map->width+j+1; // 1 1
Indices[u+3] = (i)*map->width+j+1; // 0 1
u+=4;
}
}
}
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);

/**
Render 1 0 tile
**/
glDrawElements(GL_QUADS, u, GL_UNSIGNED_SHORT, 0);

/**
1 1 Tile Updating
**/
glBindBufferARB( GL_ARRAY_BUFFER_ARB, VBOTileTexCoords );
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );
TexCoords = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY);

for(int i=1;i<map->height-1;i+=2) {
for(int j=1;j<map->width-1;j+=2) {

TexCoords[(i*map->width+j)*2] = float(tileUV[ map->get(i,j,1)*8+0 ])/tiletex->width; // 0 0 u
TexCoords[(i*map->width+j)*2+1] = float(tileUV[ map->get(i,j,1)*8+1 ])/tiletex->height; // 0 0 v

TexCoords[((i+1)*map->width+j)*2] = float(tileUV[ map->get(i,j,1)*8+2 ])/tiletex->width; // 1 0 u
TexCoords[((i+1)*map->width+j)*2+1] = float(tileUV[ map->get(i,j,1)*8+3 ])/tiletex->height; //1 0 v

TexCoords[((i+1)*map->width+j+1)*2] = float(tileUV[ map->get(i,j,1)*8+4 ])/tiletex->width; //1 1 u
TexCoords[((i+1)*map->width+j+1)*2+1] = float(tileUV[ map->get(i,j,1)*8+5 ])/tiletex->height; //1 1 v

TexCoords[(i*map->width+j+1)*2] = float(tileUV[ map->get(i,j,1)*8+6 ])/tiletex->width; //0 1 u
TexCoords[(i*map->width+j+1)*2+1] = float(tileUV[ map->get(i,j,1)*8+7 ])/tiletex->height; //0 1 v
}
}
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);

glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, VBOTileIndices); /// Use Tile Indices
Indices = (unsigned short*)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY);

//Tile is rendered upon Terrain : you can use transparent tile
u = 0;
for(int i=1;i<map->height-1;i+=2) {
for(int j=1;j<map->width-1;j+=2) {
if( map->get(i,j,1) && map->get(i,j,1) < nofObject ) { //if valid object render
Indices[u] = i*map->width+j; // 0 0
Indices[u+1] = (i+1)*map->width+j; // 1 0
Indices[u+2] = (i+1)*map->width+j+1; // 1 1
Indices[u+3] = (i)*map->width+j+1; // 0 1
u+=4;
}
}
}
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);

/**
Render 1 1 tile
**/
glDrawElements(GL_QUADS, u, GL_UNSIGNED_SHORT, 0);

/**
0 1 Tile Updating
**/
glBindBufferARB( GL_ARRAY_BUFFER_ARB, VBOTileTexCoords );
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );
TexCoords = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY);

for(int i=0;i<map->height-1;i+=2) {
for(int j=1;j<map->width-1;j+=2) {

TexCoords[(i*map->width+j)*2] = float(tileUV[ map->get(i,j,1)*8+0 ])/tiletex->width; // 0 0 u
TexCoords[(i*map->width+j)*2+1] = float(tileUV[ map->get(i,j,1)*8+1 ])/tiletex->height; // 0 0 v

TexCoords[((i+1)*map->width+j)*2] = float(tileUV[ map->get(i,j,1)*8+2 ])/tiletex->width; // 1 0 u
TexCoords[((i+1)*map->width+j)*2+1] = float(tileUV[ map->get(i,j,1)*8+3 ])/tiletex->height; //1 0 v

TexCoords[((i+1)*map->width+j+1)*2] = float(tileUV[ map->get(i,j,1)*8+4 ])/tiletex->width; //1 1 u
TexCoords[((i+1)*map->width+j+1)*2+1] = float(tileUV[ map->get(i,j,1)*8+5 ])/tiletex->height; //1 1 v

TexCoords[(i*map->width+j+1)*2] = float(tileUV[ map->get(i,j,1)*8+6 ])/tiletex->width; //0 1 u
TexCoords[(i*map->width+j+1)*2+1] = float(tileUV[ map->get(i,j,1)*8+7 ])/tiletex->height; //0 1 v
}
}
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);

glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, VBOTileIndices); /// Use Tile Indices
Indices = (unsigned short*)glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY);

//Tile is rendered upon Terrain : you can use transparent tile
u = 0;
for(int i=0;i<map->height-1;i+=2) {
for(int j=1;j<map->width-1;j+=2) {
if( map->get(i,j,1) && map->get(i,j,1) < nofObject ) { //if valid object render
Indices[u] = i*map->width+j; // 0 0
Indices[u+1] = (i+1)*map->width+j; // 1 0
Indices[u+2] = (i+1)*map->width+j+1; // 1 1
Indices[u+3] = (i)*map->width+j+1; // 0 1
u+=4;
}
}
}
glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);

/**
Render 0 1 tile
**/
glDrawElements(GL_QUADS, u, GL_UNSIGNED_SHORT, 0);
}
Messages postés
546
Date d'inscription
vendredi 13 février 2004
Statut
Membre
Dernière intervention
9 janvier 2008
1
Tu affiche combien de polygones?

Pour les processeurs 64 bits je sais pas comment ca se passe.

Tes enormes textures c'est pour calculer le multitexturing sur ta map? En effet c'est une methode tres tres gourmande! Je suis meme pas sur de pouvoir lancer ton appli sur mon pc et encore....si j'avais linux!
Messages postés
46
Date d'inscription
vendredi 14 janvier 2005
Statut
Membre
Dernière intervention
31 juillet 2006

j ai termine avec les VBOs et les Fbos
le programme tourne maintenant a vitesse variable
200fps lorsque rien ne se passe sauf translation et scale
100fps lorsque la souris bouge
20fps lors de changement du terrain

par contre le programme est tres gourmand en memoire graphique :
j'alloue 2 textures de 4096*4096 et 1 depth buffer 24bit de la meme taille

la source est un binaire pour linux est disponible ici :
http://matthias.fauconneau.googlepages.com/home

vous aurez besoin des packages/librairies suivant(es) :
SDL png zlib jpeg GL GLU

PS:en ce wui concerne la multiplication de vertex c'est tout de meme
3float vs 1 short donc 6x plus
mais ce n'est rien par rapport au 3 enorme texture que j'utilise
Afficher les 20 commentaires

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.