Foros - Stratos

Programadores => Programación gráfica => Mensaje iniciado por: Haddd en 03 de Febrero de 2004, 10:14:20 AM

Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Haddd en 03 de Febrero de 2004, 10:14:20 AM
 Colisiones de sprites al pixel por hardware

Introducción

Bien, esta técnica permite que sea el propio hardware el que te diga si hay o no colisión. La gran ventaja es que podemos rotar, escalar, hacer lo que queramos con el sprite, frente a la tradicional técnica de las máscaras. Sin embargo tiene el inconveniente de que no es tan compatible puesto que exige que el hardware soporte Querys de oclusión.

Respecto a la velocidad, hay que tener en cuenta que se dibuja dos veces el sprite, aunque una de ellas no afecta al buffer de color. Por tanto depende enteramente de la tarjeta de vídeo. Eso no debería ser un problema, porque hoy en día las tarjetas son bastante rápidas. En el ejemplo que desarrollé, no se apreciaba apenas diferencia con colisiones que sin colisiones.

Descripción

Las Querys de oclusión nos permiten saber cuantos pixel han pasado el test del zbuffer. Entonces, si tenemos dos sprites, y dibujamos el primero con z=0, y el segundo con z=0.1, si el segundo al renderizarse no pasa todos los puntos el Ztest, significa que ha habido algún Z que no se ha podido pintar porque ya había otro dibujado, y el único que podía dibujarse era el primero, por lo que hay colisión.

La lógica a seguir es la siguiente:


Activar Zbuffer ( debemos hacerlo para que funcionen las querys de oclusión)
ZFUNC=LESSEQUAL
Desactivar escritura Z

Para todos los sprites:

Renderizar el sprite con Z=0
Obtener el nº de pixels dibujados. Ahora tenemos el nº de pixels que se dibujan del sprite si no hubiera colisiones. Lo guardamos en una variable, por ejemplo PixelsSinColisionar

Ahora tenemos para cada sprite el nº de pixels que se han dibujado

Ahora se trata de comprobar aquellos que necesitamos. Normalmente comprobarmos un sprite con otros. Por ejemplo, comprobamos el muñeco protagonista con las balas.

Clear ZBuffer
Activar Zbuffer ( debemos hacerlo para que funcionen las querys de oclusión)
ZFUNC=LESSEQUAL
Activar escritura Z
Desactivar Buffer de color

Renderizar el sprite del muñeco con Z=0.

Para todos los demás sprites:

Renderizar el sprite con Z= 0.1
Obtener el nº de pixels dibujados. Aquí nos devolverá el nº que han pasado el Ztest, es decir, que no colisionan con el muñeco. Lo guardamos en una variable, por ejemplo PixelsConColision



Listo, ahora sólo tenemos que comprobar si PixelsConColision<> PixelsSinColisionar. Además como sabemos el nº de pixels sabemos el grado de "colisión", por lo que podemos hacer efectos teniendo en cuenta este valor.
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Loover en 03 de Febrero de 2004, 11:09:27 AM
 Genial. Estaría bien que lo mandaras como código de la semana, jeje. O que lo subieras a algún lado.
Un par de preguntas:
1) Al dibujar los sprites por primera vez para ver el número de píxeles, ¿lo haces con el buffer de color activado? Si es así, ¿cómo haces para que no se dibujen? Lo digo pq no debe dibujarse nada realmente hasta que sepamos que hay colisión o no.
2) ¿Dibujas todo el sprite o solo el area rectangular que entra en colisión?
3) ¿Realizas una comprobación previa por area más rápida para no esta renderizando todo el rato doblemente?

Ojala puedas preparar el código fuente de esta parte.

Un saludo!
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Malandrin en 03 de Febrero de 2004, 12:09:56 PM
   Hola,

 Si he entendido bien la comprobación de colisión la haces cuando rendeas la escena? Si es así la verdad es que no me parece una técnica muy buena por lo siguiente:

1º) Quizás sea una manía personal, pero el que un tema de la lógica --el detectar colisiones-- depende del pintado no me parece correcto. p.e. si nuestro jueguillo va a 25fps de lógica y 85fps de pintado, o perdemos 60 frames de cálculos o nos toca controlar en que momento queremos calcular las colisiones y en cuales no ( y aún así no me parece apropiado :)

2º) En una flujo normal de programa, p.e.:

           .................
           UpdatePlayer();
           UpdateEnemies();

           BeginDraw();
           DrawPlayer();
           DrawEnemies();
           EndDraw();
           ................

   Y suponiendo que la comprobación de colisiones se hiciera en el Update apropiado, tendríamos que reaccionar a la colisión en medio del pintado (ufff) que podría modificar la correcta visualización de la escena o almacenar todas las posibles colisiones y comprobarlas después del pintado, partiendo entonces el comportamiento de los bichos en 2 y además también podrían producirse visualizaciones incorrectas --porque se comprueba la colisión después del pintado--


 Si he entendido mal y la comprobación de colisiones no la haces en el pintado, pos perdona por darte la chapa :)

 Saludines.
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Haddd en 03 de Febrero de 2004, 12:59:18 PM
 Tienes toda la razón Malandrin. Para hacerlo bien bien, que no creo que nadie haga así los juegos 2D de plataformas, deberías tener en cuenta la velocidad y calcular el punto en el cual ha colisionado la caja de la bala, por ejemplo, con la del monigote. Después renderizar en esa situación y comprobar colisiones por pixel. Depende del programador si utiliza o no esta técnica...
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Zaelsius en 03 de Febrero de 2004, 01:59:00 PM
 Nadie impide utilizar el frame buffer para las colisiones, desde el módulo que controla la lógica. Ya que no estás obligado a volcar a pantalla lo que hayas pintado, se puede usar perfectamente para el cálculo de colisiones en cualquier parte del código. (Supuestamente limpiamos el frame buffer antes de cada ciclo de pintado del juego)

Otra cosa es que este método sea más o menos óptimo... todo es probar.
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Loover en 03 de Febrero de 2004, 02:28:03 PM
 Hadd, a ver si puedes responder a las 3 preguntillas esas que te puse  :P

El caso es, que creo que una ya está contestada. Creo que deberías primero verificar la zona de colisión mediante areas. Y si hay colisión, entonces hacer un SetViewPort del area de colisión y llevar a cabo ahí tu técnica, pero con el buffer de color desactivado. Si hay colisión, pues que devuelva true y ya proseguimos con los updates y el draw posterior.
Vamos, podría hacerse así:

Colisiones (); => usa BeginDraw(); y EnDraw(); para la técnica solo si hay colisión por area previa, sin dibujar nada, con el buffer de color desactivado.
UpdatePlayer();
UpdateEnemies();

BeginDraw();
DrawPlayer();
DrawEnemies();
EndDraw();

¿Podría hacerse así?
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Haddd en 03 de Febrero de 2004, 03:16:57 PM
 Sí, podría hacerse como dices. En el ejemplo que puse, si mirais el código  O_O , veréis cómo lo trato. Sólo se estudian los sprites que colisionan en el bounding box.

En el ejemplo que subí, hay 20 sprites que se desplazan por la pantalla. Con colisiones y sin colisiones apenas afecta al frame rate. Yo lo hice de la forma que está en el código, tu puedes optar por otra vía. Esta bien que se comenten utilizaciones diferentes para ver otros puntos de vista.

Yo, por ejemplo, asumo que no necesito saber si hay colisión hasta el próximo frame. Así, después de hacer el render calculo las colisiones, y en el siguiente FrameMove, miro si ha colisionado y si lo ha hecho actuo. Pero si necesitara saber en el mismo frame si ha colisionado, podría hacerlo, aunque no sería lo más óptimo, porque deberías establecer un Begin y un End del device....
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: samsaga2 en 03 de Febrero de 2004, 04:58:16 PM
 Creo que seria mejor usar el stencil buffer para detectar colision por pixel entre sprites que no los occlusion queries (que no son soportados por todas las tarjetas).
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Loover en 03 de Febrero de 2004, 05:02:16 PM
 Pues mi tarjeta no tiene stencil pero si querys, así que no es una solución genérica esa tampoco. La única que veo es RenderToTexture y lockearla, pero debe ser muy lenta.
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: BeRSeRKeR en 03 de Febrero de 2004, 05:26:20 PM
Cita de: "samsaga2"Creo que seria mejor usar el stencil buffer para detectar colision por pixel entre sprites que no los occlusion queries (que no son soportados por todas las tarjetas).
En realidad no creo que eso sea un problema ya que Haddd está orientando su motor a los pixel shaders. Y creo que cualquier aceleradora con soporte para pixel shaders, soporta occlusion queries. Al menos la GeForce3, que es la aceleradora con un soporte mínimo de pixel shaders, soporta occlusion queries.

Saludos.
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Zaelsius en 03 de Febrero de 2004, 07:05:07 PM
Cita de: "samsaga2"Creo que seria mejor usar el stencil buffer para detectar colision por pixel entre sprites que no los occlusion queries
¿Qué método propones?  
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Haddd en 03 de Febrero de 2004, 07:43:20 PM
 Aquí viene el código de las querys de oclusión

CXSprite::CXSprite(const CXString &nombre)
{
...
 if(Video.m_Informacion.m_SoportaQueryOclusion) {

  Haddd.Debug(_T("Creada la Query de oclusión del sprite"));

  HRESULT hr=Video.Device()->CreateQuery (D3DQUERYTYPE_OCCLUSION, &m_QueryOclusion);
  if(hr!=S_OK) {

   Haddd.s_Error.EstablecerYMostrar(hr,_T(""));
  }
 }
}

void CXSprite::QueryOclusion(bool iniciar)
{
if(m_QueryOclusion==NULL) return;

if(iniciar) {
 
 m_QueryOclusion->Issue (D3DISSUE_BEGIN);

 return;

}

m_QueryOclusion->Issue (D3DISSUE_END);
}

DWORD CXSprite::LeerQueryOclusion()
{
DWORD v;

if(m_QueryOclusion==NULL) return 0;

// Stupidly block until we have a query result
while (m_QueryOclusion->GetData((void *)&v, sizeof(DWORD), D3DGETDATA_FLUSH) == S_FALSE)
{
}
return v;
}


Lo demás, creo que es trivial, y ya depende de cómo tengas montados tu los sprites.
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: [EX3] en 04 de Febrero de 2004, 01:29:45 AM
 BeRSeRKeR dijo:
CitarEn realidad no creo que eso sea un problema ya que Haddd está orientando su motor a los pixel shaders. Y creo que cualquier aceleradora con soporte para pixel shaders, soporta occlusion queries. Al menos la GeForce3, que es la aceleradora con un soporte mínimo de pixel shaders, soporta occlusion queries.
Segun la comprobacion llevada a cabo por el motor de Haddd no se suponia ke mi GForce3 no soportaba Occlusion Queries? :blink:

CitarHaddd v1.0 (Feb 1 2004 19:44:36)
INICIO CXVideo::CXVideo
FIN CXVideo::CXVideo
Nº de adaptadores:1
No soporta FullScreen
No soporta FullScreen
TARJETAS Y SUS DEVICES
Tarjeta:0 3D Blaster GeForce3 Ti 200
Device:0 HAL Behavior: HW MIX SOFT NºFormatos:2
Modo:0 Modo Ventana posible 00000016 X8R8G8B8 DEPTH STENCIL 00000050 D16 0000004d D24X8 0000004b D24S8 00000047 D32
Modo:1 Modo Ventana NO posible 00000017 R5G6B5 DEPTH STENCIL 00000050 D16 0000004d D24X8 0000004b D24S8 00000047 D32
Device:1 REF Behavior: NO SOPORTA T&L NºFormatos:2
ESTE DEVICE NO CUMPLE LAS EXIGENCIAS MINIMAS DEL MOTOR
Modo:0 Modo Ventana NO posible 00000016 X8R8G8B8No soporta FullScreen
Modo:1 Modo Ventana NO posible 00000017 R5G6B5No soporta FullScreen
INICIO CXVideo_Inicializacion::CrearVentana
FIN CXVideo_Inicializacion::CrearVentana
INICIO SeleccionarDepthStencil
Depth Bits=16 Stencil Bits=0 D16
FIN SeleccionarDepthStencil
CXVideo_Inicializacion::InicializarDevice
   Behavior seleccionado:D3DCREATE_HARDWARE_VERTEXPROCESSING
CXVideo_Inicializacion::InicializarDevice
INICIO Características del Device
   Versión de SDX:31. De D3D:0900
   Versión del Adaptador:2185
   Memoria de vídeo disponible:108 MB (110592 KB)
   HAL (hw vp): 3D Blaster GeForce3 Ti 200 (740x560x8) (D16S0)
   Escritorio: Ancho=1024 Alto=768
   FullScreenGamma OK
   CanCalibrateGamma NO DISPONIBLE
   Alpha en modo Flip/Discard OK
   Nº Máximo de Streams para Vertex Buffers=16. Tamaño máximo en bytes(Stride)=256
   Nº Máximo de indexbuffer=x000fffff.
   Nº de RenderTarget simultáneos:1
   ---------TEXTURAS---------
   Utilizando formato por defecto para las texturas A8R8G8B8
   Las texturas NO necesitan ser potencias de 2
   Máx Anchura x Altura: 4096 x 4096
   Nº máximo de texturas simultáneas:4
   Soporta compresión DXT1
   Soporta compresión DXT2
   Soporta compresión DXT3
   Soporta compresión DXT4
   Soporta compresión DXT5
   Soporta Texturas volumétricas
   ---------SHADERS---------
   Nº de constantes en el vertex shader:96
   NO SOPORTA PIXEL SHADER 2.0
   NO SOPORTA PIXEL SHADER 1.4

   SI SOPORTA PIXEL SHADER 1.1. 8 constantes, 4 coordenadas de textura, 2 temporales
   NO Soporta Querys de Oclusión
FIN Características del Device
(...)
Salu2...
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: BeRSeRKeR en 04 de Febrero de 2004, 02:05:11 AM
 Si no recuerdo mal, mi GeForce3 sí soportaba occlusion queries. A ver si nVidia ha quitado el soporte en sus últimos drivers. Porque recuerdo que probé aquella demo de Delphi3D.net que utilizaba occlusion queries y funcionaba perfectamente.

Buscando, he encontrado algo que lo confirma:

CitarTo run OpenCSG well, you should have graphics hardware with lots of fill rate. NVidia graphics hardware since GeForce and ATI Radeon qualify. The OpenCSG::OcclusionQuery option obviously requires occlusion queries, which are available since Radeon 9x00 (x>=5) and GeForce3 (beware that the GeForce4MX counts as GeForce2!).

También lo puedes ver en esta página donde hay una demo sobre occlusion queries.

Así que, como he dicho, lo único que se me ocurre es que nVidia haya eliminado dicha extensión en los últimos drivers...

Si puedes, prueba la demo de la última página que he puesto, a ver si funciona.

Saludos.
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: Loover en 04 de Febrero de 2004, 11:14:06 AM
 
CitarRadeon 9x00 (x>=5)
Pues tengo una Radeon 7200 y sí tengo OQ
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: [EX3] en 04 de Febrero de 2004, 03:35:48 PM
 BeRSeRKeR, ke version de los drivers de nVidia tienes instalada? yo no tengo la ultima instalada por temas de rendimiento, ya ke las ultimas versiones me bajan el rendimiento de todos los juegos. Tengo instalada la primera version ke salio para xp de los drivers (vamos, la ke me venia en el CD de instalacion) ya ke con esta nunca he tenido problemas como con las versiones posteriores.

Salu2...
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: BeRSeRKeR en 04 de Febrero de 2004, 03:57:27 PM
 La verdad es que no recuerdo qué versión tenía instalada ya que desde hace unos meses tengo una Radeon 9600...

De todas formas, para comprobar si es que la GeForce3 soporta sólo occlusion queries en OpenGL a través de la extensión de nVidia pero no en Direct3D, prueba esta demo en OpenGL y esta otra en Direct3D. A ver que pasa.

Por cierto, para probar la demo de ATI (la de Direct3D), necesitarás poner este archivo X que contiene una esfera en el directorio del ejecutable. Se les olvidó incluirla en el paquete... :D

De todas formas, si la demo de Haddd te dice que no soporta occlusion queries, no hay razón alguna para pensar que con la demo de ATI te vaya a funcionar. El caso es comprobar si la GeForce3 sí soporta occlusion queries a través de la extensión de OpenGL de nVidia.

Saludos.
Título: Explicacíón: Colisión De Sprites Al Pixel Por Hard
Publicado por: [EX3] en 05 de Febrero de 2004, 03:07:41 PM
 Vale, problema localizado en los drivers, tan solo por lo ke he leido en la web de la demo (y tras probar la demo en si)

CitarRequires GeForce3 or better (no 4MX) and Nvidia driver 27.xx or later.

Veo ke el problema lo pueden tener los drivers por ser una version inferior a la 27.xx (tengo instalada la 21.85, asi ke seguramente si soporte Occlusion Queries.

Gracias BeRSeRKeR ;)

Salu2...