Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Profundidad en OpenGL con Proyección ortogonal

Iniciado por javiel, 27 de Marzo de 2007, 07:44:32 PM

« anterior - próximo »

javiel

Llevo mucho tiempo comiendo el coco con esto y es que no me sale. A ver si me podéis ayudar por favor. Tengo muy pocos conocimientos de OpenGL y empecé a trastearlo hace un tiempo y ahora vuelvo de nuevo.

La cosa es que estoy haciendo un juego en 2D pero usando opengl con SDL. La cuestión es que uso proyección ortogonal y quiero usar la profundidad de los elementos para poder ordenar los sprites.

La cosa es que uso glTranslatef, y cuando le paso en el último parámetro el indice Z, si no es 0, no me sale el sprite.

Estoy haciendo un montón de pruebas pero no puedo. Creo que es algo con el glEnable(GL_DEPTH_TEST), pero es que no doy con la tecla. A lo mejor no es ni eso

¿alquien me puede orientar más o menos para saber lo que hacer?

Coloco a continuación un código con el que estoy probando para ver si os orienta un poco

Se que es un poco rollo leer el código, pero os agradezco mucho vuestra ayuda

muchas gracias de antemano


#ifdef WIN32

#define WIN32_LEAN_AND_MEAN

#include <windows.h>

#endif

#if defined(__APPLE__) && defined(__MACH__)

#include <OpenGL/gl.h>   // Header File For The OpenGL32 Library

#include <OpenGL/glu.h>   // Header File For The GLu32 Library

#else

#include <GL/gl.h>   // Header File For The OpenGL32 Library

#include <GL/glu.h>   // Header File For The GLu32 Library

#endif

#include "SDL.h"

#include <SDL_image.h>

#include <stdlib.h>





typedef struct

{

   GLuint texture;

   int w, h;

   int w_or, h_or;

   int posx, posy;

} Textura;



Textura tex1, tex2;





SDL_Surface *LoadTex(char *filename, Textura *tex)

{

   //Uint8 *rowhi, *rowlo;

   //Uint8 *tmpbuf, tmpch;

   SDL_Surface *image, *temp;

   int i, j;



   //image = SDL_LoadBMP(filename);

   temp = IMG_Load(filename);

   if ( temp == NULL ) {

       fprintf(stderr, "Unable to load %s: %s\n", filename, SDL_GetError());

       return(NULL);

   }

   

   tex->w = 512;

   tex->h = 512;

   Uint32 saved_flags;

   Uint8  saved_alpha;

 

#if SDL_BYTEORDER == SDL_BIG_ENDIAN

     image = SDL_CreateRGBSurface(SDL_SWSURFACE, tex->w, tex->h, temp->format->BitsPerPixel,

                                 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);

#else

     image = SDL_CreateRGBSurface(SDL_SWSURFACE, tex->w, tex->h, temp->format->BitsPerPixel,

                                 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);

#endif



   /* Save the alpha blending attributes */

   saved_flags = temp->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);

   saved_alpha = temp->format->alpha;

   if ( (saved_flags & SDL_SRCALPHA)

      == SDL_SRCALPHA )

   {

   SDL_SetAlpha(temp, 0, 0);

   }

   

   int colorkey = SDL_MapRGB(temp->format, 255, 0, 255);

   SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);

   SDL_FillRect(image, 0, colorkey);

   

   SDL_BlitSurface(temp, 0, image, 0);

   

   /* Restore the alpha blending attributes */

   if ( (saved_flags & SDL_SRCALPHA)

      == SDL_SRCALPHA )

   {

   SDL_SetAlpha(temp, saved_flags, saved_alpha);

   }





   tex->w_or = temp->w;

   tex->h_or = temp->h;



   SDL_FreeSurface(temp);

   return(image);

}



void LoadGLTextures(void)

{   

   

   SDL_Surface *surf;

   

   surf = LoadTex("circulo.png", &tex1);

   if (!surf) {

       SDL_Quit();

   }

   

   tex1.posx = 320;

   tex1.posy = 240;



   glGenTextures(1, &tex1.texture);

   glBindTexture(GL_TEXTURE_2D, tex1.texture);



   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture



   glTexImage2D(GL_TEXTURE_2D, 0, 4, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);

   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);

   

   

   surf = LoadTex("alien.png", &tex2);

   if (!surf) {

       SDL_Quit();

   }

   

   tex2.posx = 315;

   tex2.posy = 235;



   glGenTextures(1, &tex2.texture);

   glBindTexture(GL_TEXTURE_2D, tex2.texture);

   

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture



   glTexImage2D(GL_TEXTURE_2D, 0, 4, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);

   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);    



};



void InitGL(int Width, int Height)

{

   glViewport(0, 0, Width, Height);

   LoadGLTextures();

   glEnable(GL_TEXTURE_2D);

   glClearColor(0.0f, 0.0f, 1.0f, 0.0f);

   //glClearDepth(1.0);

   //glDepthFunc(GL_LESS);

   //glEnable(GL_DEPTH_TEST);



   glShadeModel(GL_SMOOTH);

   

   glMatrixMode(GL_PROJECTION);

   glLoadIdentity();

   glOrtho(0, Width, Height, 0, 0, 1);    

   

   glMatrixMode(GL_MODELVIEW);

   

}



/* Dibujar textura */

void DrawGLTexture(Textura *tex)

{

   glPushMatrix();

   

   glEnable(GL_TEXTURE_2D);

   glEnable(GL_BLEND);

   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //GL_ONE_MINUS_SRC_ALPHA
   
   //glColor4ub(255,255,255,100);



   glBindTexture(GL_TEXTURE_2D, tex->texture);

 

   glTranslatef(tex->posx,tex->posy,0);  



   float relW = (float)tex->w_or/(float)tex->w;

   float relH = (float)tex->h_or/(float)tex->h;



 

   glBegin(GL_QUADS);

     glTexCoord2f(0.0f, relH);

     glVertex2f(-tex->w_or/2, tex->h_or/2);      

     glTexCoord2f(relW, relH);

     glVertex2f(tex->w_or/2, tex->h_or/2);

     glTexCoord2f(relW, 0.0f);

     glVertex2f(tex->w_or/2, -tex->h_or/2);

     glTexCoord2f(0.0f, 0.0f);

     glVertex2f(-tex->w_or/2,-tex->h_or/2);

   glEnd();  

   

   glDisable(GL_BLEND);

   glDisable(GL_TEXTURE_2D);

   

   glPopMatrix();

}



void DrawGLScene()

{

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);      // Clear The Screen And The Depth Buffer

   glLoadIdentity();            // Reset The View



   DrawGLTexture(&tex2);

   DrawGLTexture(&tex1);



   SDL_GL_SwapBuffers();

}



int main(int argc, char **argv)

{  

 int done;

 Uint8 *keys;



 /* Initialize SDL for video output */

 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {

   fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());

   //exit(1);

 }



 /* Create a 640x480 OpenGL screen */

 if ( SDL_SetVideoMode(640, 480, 0, SDL_OPENGL) == NULL ) {

   fprintf(stderr, "Unable to create OpenGL screen: %s\n", SDL_GetError());

   SDL_Quit();

   //exit(2);

 }



 /* Set the title bar in environments that support it */

 SDL_WM_SetCaption("Prueba OpenGL", NULL);



 /* Loop, drawing and checking events */

 InitGL(640, 480);

 done = 0;

 int speed = 1;

 while ( ! done ) {

   DrawGLScene();



   /* This could go in a separate function */

   { SDL_Event event;

     while ( SDL_PollEvent(&event) ) {

       if ( event.type == SDL_QUIT ) {

         done = 1;

       }



       if ( event.type == SDL_KEYDOWN ) {

         if ( event.key.keysym.sym == SDLK_ESCAPE ) {

           done = 1;

         }

       }

     }

       

   }

 }

 SDL_Quit();

 return 1;

}
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

[EX3]

Yo intente hacer lo mismo en Direct3D mediante el zBuffer, cosa que no logre por ciertos efectos innesperados, y al final opte por hacer una lista de ordenado de llamadas donde almaceno los parametros de las llamadas de dibujo y luego los proceso segun orden en la rutina de dibujo de la escena.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

ALRAZ

En la función InitGL
tienes:


glOrtho(0, Width, Height, 0, 0, 1);


los últimos dos parámetros son la distancia mínima y máxima para Z, por lo que le estás diciendo que el valor mínimo para la profundidad es 0 y el máximo 1.
Intenta poner algo como 100 en lugar de ese 1.

Por cierto, creo que tienes mal un parámetro, según yo, es:

glOrtho (0 , ScrWidth, 0, ScrHeight, DrawNearDistance, DrawFarDistance);


Además de eso, claro, tendrás que activar el Depth test si no has ordenado previamente tus objetos

javiel

Bueno, gracias, ya he conseguido que me funcione lo del DEPTH, pero se me ha traido otro problema

Yo tengo dos texturas que son pngs transparentes. Cuando le pongo el DEPTH la parte transparente me la pone como el color de fondo.

Pongo un par de imágenes. Esta es cuando le pongo el depth, los transparentes no salen pero puedo ordenar con el indiceZ:



Esta es quitando el depth, puedo ordenar con el indiceZ pero no me salen las partes transparentes



A ver si doy con esto, pq es que no puedo

Muchas gracias. Pongo el código de nuevo con el indiceZ


typedef struct
{
   GLuint texture;
   int w, h;
   int w_or, h_or;
   int posx, posy;
   int indiceZ;
} Textura;

Textura tex1, tex2;


SDL_Surface *LoadTex(char *filename, Textura *tex)
{
   //Uint8 *rowhi, *rowlo;
   //Uint8 *tmpbuf, tmpch;
   SDL_Surface *image, *temp;
   int i, j;

   //image = SDL_LoadBMP(filename);
   temp = IMG_Load(filename);
   if ( temp == NULL ) {
       fprintf(stderr, "Unable to load %s: %s\n", filename, SDL_GetError());
       return(NULL);
   }
   
   tex->w = 512;
   tex->h = 512;
   Uint32 saved_flags;
   Uint8  saved_alpha;
 
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
     image = SDL_CreateRGBSurface(SDL_SWSURFACE, tex->w, tex->h, temp->format->BitsPerPixel,
                                 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
#else
     image = SDL_CreateRGBSurface(SDL_SWSURFACE, tex->w, tex->h, temp->format->BitsPerPixel,
                                 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
#endif

   /* Save the alpha blending attributes */
   saved_flags = temp->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
   saved_alpha = temp->format->alpha;
   if ( (saved_flags & SDL_SRCALPHA)
      == SDL_SRCALPHA )
   {
   SDL_SetAlpha(temp, 0, 0);
   }
   
int colorkey = SDL_MapRGB(temp->format, 255, 0, 255);
SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
SDL_FillRect(image, 0, colorkey);
   
   SDL_BlitSurface(temp, 0, image, 0);
   
   /* Restore the alpha blending attributes */
   if ( (saved_flags & SDL_SRCALPHA)
      == SDL_SRCALPHA )
   {
   SDL_SetAlpha(temp, saved_flags, saved_alpha);
   }


   tex->w_or = temp->w;
   tex->h_or = temp->h;

   SDL_FreeSurface(temp);
   return(image);
}

void LoadGLTextures(void)
{
   
   SDL_Surface *surf;
   
   surf = LoadTex("circulo.png", &tex1);
   if (!surf) {
       SDL_Quit();
   }
   
   tex1.posx = 320;
   tex1.posy = 240;
   tex1.indiceZ = -2;

   glGenTextures(1, &tex1.texture);
   glBindTexture(GL_TEXTURE_2D, tex1.texture);

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture

   glTexImage2D(GL_TEXTURE_2D, 0, 4, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
   
   
   surf = LoadTex("alien.png", &tex2);
   if (!surf) {
       SDL_Quit();
   }
   
   tex2.posx = 315;
   tex2.posy = 235;
   tex2.indiceZ = -1;

   glGenTextures(1, &tex2.texture);
   glBindTexture(GL_TEXTURE_2D, tex2.texture);
   
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture

   glTexImage2D(GL_TEXTURE_2D, 0, 4, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels);
   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);    

};

void InitGL(int Width, int Height)
{
   glViewport(0, 0, Width, Height);
   LoadGLTextures();
   glEnable(GL_TEXTURE_2D);
   glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
   glClearDepth(1);
   glDepthFunc(GL_LESS);
   glEnable(GL_DEPTH_TEST);


   glShadeModel(GL_SMOOTH);
   
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0, Width, Height, 0, 0, 100);    
   
   glMatrixMode(GL_MODELVIEW);
   
}

/* Dibujar textura */
void DrawGLTexture(Textura *tex)
{
   glPushMatrix();
         
   glEnable(GL_TEXTURE_2D);
   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //GL_ONE_MINUS_SRC_ALPHA

   //glColor4ub(255,255,255,100);

   glBindTexture(GL_TEXTURE_2D, tex->texture);
   
   
   glTranslatef(tex->posx, tex->posy, tex->indiceZ);  
   
   
   
   float relW = (float)tex->w_or/(float)tex->w;
   float relH = (float)tex->h_or/(float)tex->h;

 
   glBegin(GL_QUADS);
     glTexCoord2f(0.0f, relH);
     glVertex2f(-tex->w_or/2, tex->h_or/2);      
     glTexCoord2f(relW, relH);
     glVertex2f(tex->w_or/2, tex->h_or/2);
     glTexCoord2f(relW, 0.0f);
     glVertex2f(tex->w_or/2, -tex->h_or/2);
     glTexCoord2f(0.0f, 0.0f);
     glVertex2f(-tex->w_or/2,-tex->h_or/2);
   glEnd();  
   
   glDisable(GL_BLEND);
   glDisable(GL_TEXTURE_2D);
   
   glPopMatrix();
}

void DrawGLScene()
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
   glLoadIdentity(); // Reset The View

   DrawGLTexture(&tex2);
   DrawGLTexture(&tex1);

   SDL_GL_SwapBuffers();
}

int main(int argc, char **argv)
{  
 int done;
 Uint8 *keys;

 /* Initialize SDL for video output */
 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
   fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
   //exit(1);
 }

 /* Create a 640x480 OpenGL screen */
 if ( SDL_SetVideoMode(640, 480, 0, SDL_OPENGL) == NULL ) {
   fprintf(stderr, "Unable to create OpenGL screen: %s\n", SDL_GetError());
   SDL_Quit();
   //exit(2);
 }

 /* Set the title bar in environments that support it */
 SDL_WM_SetCaption("Prueba OpenGL", NULL);

 /* Loop, drawing and checking events */
 InitGL(640, 480);
 done = 0;
 int speed = 1;
 while ( ! done ) {
   DrawGLScene();

   /* This could go in a separate function */
   { SDL_Event event;
     while ( SDL_PollEvent(&event) ) {
       if ( event.type == SDL_QUIT ) {
         done = 1;
       }

       if ( event.type == SDL_KEYDOWN ) {
         if ( event.key.keysym.sym == SDLK_ESCAPE ) {
           done = 1;
         }
       }
     }
       
   }
 }
 SDL_Quit();
 return 1;
}
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

tamat

El tema de las alphas es problematico cuando se mezcla con ztest. Si analizas el problema en papel te daras cuenta de que si pintas un pixel semitransparente (actualizando la Z) luego al pintar un pixel que está detras el ztest lo descartará porque en teoría está ocluido, cuando en realidad deberia verse mezclado.

Hay dos soluciones a eso, la primera es pintar en orden de Z, puede parecer dificil pero no lo es, basta con que crees una lista con todos los sprites que tienen alpha y calcules el vector que va desde el centro del sprite hasta la posicion de la camara, luego los ordenas en funcion del modulo de ese vector y ya tienes el orden de pintado.

La otra solucion es usar alphas duras, es decir, o transparente o no transparente, usando el Alpha Test, en tal caso el Zbuffer no se te actualizará si un pixel es 100% transparente, pero las alphas seran demasiado afiladas y eso suele quedar mal.
Por un stratos menos tenso

javiel

entoces es imposible hacerlo así directamente ¿no?

tendré que crearme yo mismo el orden de los sprites

gracias y un saludo
uper-Tirititran: el superhéroe gaditano (http://www.super-tirititran.com)

marcode

Yo creo que con dibujar todos los sprites que tengan alpha al final es suficiente.
size=9]afortunadamente siempre ha habido alguien dispuesto a reinventar la rueda, de lo contrario seguiríamos usando un disco de piedra con un agujero.[/size]

Fran

Tienes que dibujar primero todo lo opaco con el test de profundidad activado. Una vez hayas hecho esto, dibujas todo lo transparente con el buffer de profundidad desactivado y/o bloqueado a la escritura.






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.