Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Explicacíón: Colisión De Sprites Al Pixel Por Hard

Iniciado por Haddd, 03 de Febrero de 2004, 10:14:20 AM

« anterior - próximo »

Haddd

 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.

Loover

 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!
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

Malandrin

   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.

Haddd

 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...

Zaelsius

 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.

Loover

 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í?
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

Haddd

 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....

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).

Loover

 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.
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

BeRSeRKeR

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.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

Zaelsius

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?  

Haddd

 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.

[EX3]

 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...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

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

BeRSeRKeR

 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.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

Loover

 
CitarRadeon 9x00 (x>=5)
Pues tengo una Radeon 7200 y sí tengo OQ
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!






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.