Foros - Stratos

Programadores => Programación gráfica => Mensaje iniciado por: KACHORRO en 25 de Octubre de 2005, 07:32:55 PM

Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 25 de Octubre de 2005, 07:32:55 PM
 En mi hilo anterior la gente comenzó a darme consejos para optimizar Direct3D.
Viendo la cantidad de posibilidades e ideas de todos, he pensado que sería mejor un hilo dedicado al tema.
La forma en que dibujo los sprites 2D la he cogido de GameDev.net

El codigo que define los vertices y dibuja la textura es este:

Citar
void BlitD3D (IDirect3DTexture9 *texture, RECT *rDest,  D3DCOLOR vertexColour, float rotate)
{ TLVERTEX* vertices;

  //Lock the vertex buffer
  vertexBuffer->Lock(0, 0, (void**)&vertices, NULL);

  vertices[0].colour = vertexColour;
  vertices[0].x = (float) rDest->left - 0.5f;
  vertices[0].y = (float) rDest->top - 0.5f;
  vertices[0].z = 0.0f;
  vertices[0].rhw = 1.0f;
  vertices[0].u = 0.0f;
  vertices[0].v = 0.0f;

  vertices[1].colour = vertexColour;
  vertices[1].x = (float) rDest->right - 0.5f;
  vertices[1].y = (float) rDest->top - 0.5f;
  vertices[1].z = 0.0f;
  vertices[1].rhw = 1.0f;
  vertices[1].u = 1.0f;
  vertices[1].v = 0.0f;

  vertices[2].colour = vertexColour;
  vertices[2].x = (float) rDest->right - 0.5f;
  vertices[2].y = (float) rDest->bottom - 0.5f;
  vertices[2].z = 0.0f;
  vertices[2].rhw = 1.0f;
  vertices[2].u = 1.0f;
  vertices[2].v = 1.0f;

  vertices[3].colour = vertexColour;
  vertices[3].x = (float) rDest->left - 0.5f;
  vertices[3].y = (float) rDest->bottom - 0.5f;
  vertices[3].z = 0.0f;
  vertices[3].rhw = 1.0f;
  vertices[3].u = 0.0f;
  vertices[3].v = 1.0f;
 
  //Unlock the vertex buffer
  vertexBuffer->Unlock();

  //Set texture
  DEVICE->SetTexture (0, texture);

  //Draw image
  DEVICE->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2);
}

¿Alguna idea para optimizar esto?
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 26 de Octubre de 2005, 05:20:25 AM
 Me he dado cuenta de otro problema con esto del 2D en D3D...

Resulta que las texturas tienen que ser de un tamaño potencia de 2 (32x32, 64x64, 128x128...etc).

El caso es que yo uso sprites de cualquier tamaño, y logicamente, la textura asociada a un sprite de 33x33 es forzosamente de 64x64 pixeles... esto realmente no me importa, ya que intentaría hacer los sprites lo mas ajustados posible a los tamaños.

El problema lo tengo en el dibujado, que dibujo la textura completa... y claro, supongo que dibujar el resto de la textura, aunque no se vea, consumirá tiempo de proceso.

¿Se puede dibujar un rectangulo de la textura de cualquier tamaño en un quad de ese tamaño?
Título: Optimizar Direct3d Para 2d
Publicado por: fiero en 26 de Octubre de 2005, 06:39:17 AM
 
Cita de: "KACHORRO"El problema lo tengo en el dibujado, que dibujo la textura completa... y claro, supongo que dibujar el resto de la textura, aunque no se vea, consumirá tiempo de proceso.

¿Se puede dibujar un rectangulo de la textura de cualquier tamaño en un quad de ese tamaño?
La tarjeta consume el tiempo por el hecho de renderizar los dos triángulos. Le da lo mismo lo que haya en la textura, o si la textura que se vé entera o se vé solo un trozo.

Si tus sprites ocupan menos de una potencia de 2 puedes jugar con las coordenadas de la textura. Es decir, si tu sprite tiene 200 pixels de ancho y se te ha guardado en una zona de 256 pixels, en vez de ponerle 1.0f a la coordenada U, le pondrás vertices[1].u=0.78125f (200/256=0.78125). Puedes jugar con eso también para hacer animaciones por ejemplo, metiendo todos los frames de la animación de un sprite en una textura y desplazando las coordenadas U V para que se vea solo el trozo de textura que te interesa en cada momento.

un saludo

[EDITO] Prueba de edición
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 26 de Octubre de 2005, 07:41:31 AM
 No sé si lo he entendido bien...

quieres decir que puedo tener una textura de 64x64, con un dibujo de tamaño 50x38

¿puedo entonces hacer un quad de 50x38 y mostrar ese rectangulo de la textura?

¿qué son el parámetro u y v de los vertices exactamente?
Título: Optimizar Direct3d Para 2d
Publicado por: fiero en 26 de Octubre de 2005, 08:54:59 AM
 los parámetros u y v son las coordenadas de la textura, o sea "donde se posiciona dentro de la textura" ese vertice. Se definen con un número flotante que va de 0.0 a 1.0 (si vale más de 1.0, la textura se repite, pero bueno, olvidemonos ahora de esas cosas). La U define las coordenadas X de la textura y la V las coordenadas Y de la textura.

Si pones 0.0 en U, estas apuntando al pixel 0 de la textura (en X), y si pones 1.0 estás apuntando al último pixel. Si por ejemplo tienes una textura de 64 pixeles de ancho y pones 0.5 en U, ese vertice tendrá la coordenada del pixel 32.

Si tienes una textura de 64x64 y tu sprite solo mide 50 x 38, puedes hacer un quad de 50x38 pixeles en la pantalla y asignarle las coordenadas u=0.0 y v=0.0 para la esquina superior izquierda y u=0.78 (50/64) v=0.59 (38/64) para la esquina inferior derecha.
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 26 de Octubre de 2005, 09:28:33 AM
 
:D

Gracias ... ahora lo veo claro.
Es que eso de que fuera entre 0.0 y 1.0 me tenia intrigado.
Ahora podré dibujar sólo el sprite y no la textura entera con el borde transparente. (que encima me provocaba tener que calcular el borde sobrante para ajustar el tamaño del quad al de la textura a la hora de dibujar).


Título: Optimizar Direct3d Para 2d
Publicado por: AK47 en 26 de Octubre de 2005, 09:40:05 AM
 Saludos
Yo creo que aqui faltan los comentarios de TheAzazel, que tendra su experiencia con todos estos asuntos... Aunque tambien podrias tirar de su motor, no?
En cuanto a los asuntos de Direct3D, seria conveniente que agruparas los sprites por texturas, ya que cambiar de textura en cada blit resta mucho rendimiento. Tambien seria interesante empaquetar todos los sprites en un vertex buffer y dibujarlos de golpe, en vez de una llamada a DrawPrimitive por cada uno.
Por ejemplo podrias tener un vector de listas de vertices con un tamaño igual al numero de texturas. Cada vez que hicieses blit se usaria la textura para indexar en ese vector, y se añadirian los vertices del sprite a la lista de vertices de ese indice. Cuando ya se hayan hecho todos los blit del frame, recorres el vector y metes los vertices de cada grupo en el vertex buffer y los dibujas, todos de golpe. Asi activarias cada textura una unica vez por frame. Para el asunto del alpha blending puedes usar otro vector.
A ver si te vale para algo toda esta chapa ;)

Hasta pronto.
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 26 de Octubre de 2005, 11:11:49 AM
 ¿cual es el motor de the azazel? ¿donde hay info?

aunque sinceramente, ya que estoy puesto, me gustaria programar el mio propio, salvo que el de The Azazel sea la repera y sea irresistible el cambio...
Título: Optimizar Direct3d Para 2d
Publicado por: TheAzazel en 26 de Octubre de 2005, 12:00:20 PM
 Creo que en un antiguo post, kachorro ya hablo de que engine usar y por lo que parece... solo podremos ver la nueva abadia sobre windows...(como estas usando d3d :P).

No se si te lo dije ya antes pero parece que a ti lo que mas te interesa es terminar tu juego, asi que no se porque te has puesto a crearte tu mismo el "engine" que te lo facilite... creo que si querias haber usado d3d podrias haber tirado de la looverlib que ya te facilita bastante el tema y no te volveras loco.
Incluso, si lo querias multiplataforma...que menos que hacerlo sobre SDL? y si te pones..pues CRM32Pro que no creo que necesites nada mas y te podrias poner directamente con el juego.

Sobre lo que te cuenta Ak47... tiene toda la razon del mundo... hacer cambios de textura es muy lento, de d3d no se nada, pero de opengl si, y conozco la implementacion de glsdl donde han incluido un "manager de texturas" que funciona automaticamente... tu vas cargando tus superficies 2d con los sprites de cualquier tamano y este manager las va colocando en texturas de por ejemplo, 512x512, recortandolas, poniendo varios en el la misma, de forma que tengas el minimo de texturas con todos tus sprites. Este sistema es algo complejo de implementar pero es la mejor via. Lo que desconozco es si D3DSprite internamente hara algo de esto o no... pero me da que no hace nada  de ello, por lo tanto, a ti glSDL te vendria de perlas :) y como no...CRM32Pro jeje, asi hasta en Linux(y en un futuro MacOS) podrian disfrutar de la nueva Abadia....

Saludos
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 26 de Octubre de 2005, 01:39:31 PM
 Ciertamente tienes razón... a mi me interesa terminar el juego, y parte de esta intencíón estaba motivada porque ya tenia el engine en directdraw. Sin embargo el paso del tiempo ya las necesidades técnicas me obligan a migrar lo ya hecho a un motor más potente, que me proporcione algunas ventajas como las transparecias o los filtros por hard.

Dado que el engine que ya tenia hecho, al ser completamente en 2D, sólo necesitaba de un put_sprite y poco mas, su migración a otra plataforma no es demasiado dificil (yo mismo lo he hecho a opengl y a direct3d en una semana y sin tener mucha idea de ambos, como podeis comprobar por mis ineptas dudas en el foro).

Pero ya que estoy pringado, pues termino de pringarme con mi propio engine, sobre todo porque me da más libertad (y ciertamente, más quebraderos de cabeza, pero directamente proporcionales con la satisfaccion por el trabajo propio).

No obstante tomo nota sobre glDSL y CMR32Pro. Les voy a echar un serio vistazo.

Muchas gracias por todo.

En cualquier caso, ya que lo tengo en direct3d, pues me gustaria optimizarlo. Y prácticamente tb lo tengo en OpenGL, asi que no veo por que va a ser solo para Windows... pero tiempo al tiempo.

Título: Optimizar Direct3d Para 2d
Publicado por: zupervaca en 26 de Octubre de 2005, 03:56:09 PM
 KACHORRO ya te comente el problema de la potencia de 2 en el otro hilo que habias creado, empiezo a ver claro que mis post sencillamente no son leidos

saludos
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 26 de Octubre de 2005, 05:28:20 PM
 Te equivocas zupervaca, es por post como los tuyos por los que sigo usando el foro de stratos y creando nuevos hilos. Muchas gracias.

Si te fijas bien, el problema de las texturas de potencia de 2 que tú me comentabas se refería al contexto dentro del uso de la clase Id3dxsprite , la cual no conseguí echar andar (probablemente por el motivo que tú me comentaste), y que cuando leí tu post, ya era tarde, pues fruto de mi desesperación el domingo, ya habia implementado mi propia clase sprite (aunque fuera fruto de un copy y paste de GameDev :-) )

No obstante el problema de las surfaces potencia de 2 es intrínseco a direct3d y opengl, puesto que es originario en la forma de funcionar de las tarjetas 3D. Así pues, me lo volví a encontrar, pero esta vez en mi propia clase sprite (contexto de este hilo del foro).

Esta vez simplemente era como evitar dibujar toda la textura para dibujar sólamente el gráfico que me interesaba.

Y, de verdad, cuando hago alguna consulta en este u otro foro, deberías ver las veces que vuelvo a consultar los hilos para leer las respuestas, aún a sabiendas de que no voy a encontrar ninguna nueva, y suelo leerme las antiguas una y otra vez. Incluidas, aunque no lo creas, las tuyas.

Y de nuevo reitero mi agradecimiento, a ti, y a todos los que en este y otros foros, pierden una pizca de su tiempo en ayudar a gente como yo, que en muchos casos por mera ignorancia, y en otros por suprema vagueza, hacemos uso y abuso de los mismos.

Un saludo !!  (ole)  
Título: Optimizar Direct3d Para 2d
Publicado por: Loover en 28 de Octubre de 2005, 01:51:18 AM
 El tema de renderizar imágenes de cualquier tamaño en todas las tarjetas no es tan trivial como podría parecer al principio.

Echale un vistazo al código fuente de mi libreria que para eso es Open Source. Lo que yo hago es partir las imágenes en bloques (cada bloque una textura) según convenga según el máximo de textura permitido por la tarjeta del usuario así como del tamaño de la imagen. También hay una opción para permitir especificar el tamaño de bloque, que puede ser util por ejemplo para fondos scrolleables.

De esta manera resuelves de un plumazo varias cosas: bliteado de imágenes a cualquier tamaño (todas sobre texturas), scrolls, fuentes de bloques, etc. Es más, Looverlib permite descartar que bloques quedan fuera de la region de dibujo incluso cuando la imagen esta rotada o escalada.

Todas las clases de Looverlib utilizan la clase LOV_Surface (una imagen partida en bloques) para animaciones, etc.

Saludos!

PD: Lo que te cuento está en la clase "LOV_SurfaceManager" del código fuente de LooverLib.
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 28 de Octubre de 2005, 05:31:29 AM
 Gracias. Le echaré un vistazo.
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 28 de Octubre de 2005, 06:33:52 AM
 A todo esto... entre tanta optimización... no estoy midiendo ningún resultado :P

He visto la función timeGetTime() que te devuelve el lapso de tiempo en milisegundos.

Así que he pensado lo siguiente:

tiempo_inicio=timeGetTime();
.....
render y programa
.....
tiempo_final=timeGetTime();

unframe=(tiempo_final-tiempo_inicial)/1000; //esto son los segundos que tarda un frame
fps=1/unframe; //esto me da los frames por segundo

¿es correcto?



Título: Optimizar Direct3d Para 2d
Publicado por: Ray en 28 de Octubre de 2005, 11:01:22 AM
 Creo que podría ser correcto pero no se si con la suficiente precisión. Supongamos que el juego corre a 100pfs, cada pasada tardará 10 milésimas aprox.

unframe = 10.0 / 1000 = 0.01;
fps = 1.0 / unframe = 100;

o lo que es lo mismo  1000.0 / 10 = 100 fps;

hasta aquí bien, el problema es que seguramente cada vez te va a dar un resultado diferente en milésimas, 8, 9, 10, 11, 12.., de manera que si el valor es por ejemplo 8 aumenta en 25 los fps:

fps = 1000.0 / 8 = 125;

Todas estas variaciones vistas en pantalla serán un baile de cifras a una velocidad imposible de leer y que no te va a ser muy útil. Lo mejor es llevar un contador de frames,y visualizarlo cada vez que transcurre un segundo, te pongo un ejemplo sencillo aunque existen formas de hacerlo mejor.


void fps()
{
static DWORD OldTime=timeGetTime();
static DWORD FrameCount=0;
static DWORD fps=75;

DWORD NewTime = timeGetTime();

if (NewTime - OldTime >= 1000) {

  fps = FrameCount;

  FrameCount=0;

  OldTime = NewTime;
  }

FrameCount++;

// Visualizar fps
}

Título: Optimizar Direct3d Para 2d
Publicado por: pekul en 28 de Octubre de 2005, 08:51:49 PM
 Por qué se programa 2d utilizando 3d? d3d sigue teniendo las herramientas 2d de directdraw no? que ventaja tiene utilizar 3d para simular 2d?  
Título: Optimizar Direct3d Para 2d
Publicado por: [EX3] en 28 de Octubre de 2005, 09:49:25 PM
 
Cita de: "pekul"Por qué se programa 2d utilizando 3d?
Buena pregunta. Para aprovechar la aceleracion por hardware y asi lograr potencia en operaciones que son costosas si se hicieran a nivel de software, entre ellas el alphablending por ejemplo. En resumen, se trata de quitarle todo el trabajo posible a la CPU repartiendo el trabajo entre la CPU, que haria de todo un poco, y entre la GPU (procesador de la tarjeta grafica) que seria la que se llevaria el trabajo de todas las operaciones graficas.

Cita de: "pekul"d3d sigue teniendo las herramientas 2d de directdraw no?
No. La mecanica dista mucho de ser la de DirectDraw. En DirectDraw bliteas mapas de bits en superficies. En D3D montas texturas sobre poligonos en un plano ortogonal y que renderizas en pantalla. Seria una especie de "bliteo" pero un poco mas complejo.

Cita de: "pekul"que ventaja tiene utilizar 3d para simular 2d?
Ventajas como dije antes las que te brinda aprovechar la aceleracion por hardware de la tarjeta grafica, ventajas para realizar operaciones como:
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 29 de Octubre de 2005, 07:55:31 AM
 EX3 ha expuesto muy bien los motivos...

aunque yo voy a dar uno mas... DirectDraw dejó de soportarse en DirectX 7.0 y aunque su funcionamiento era y sigue siendo muy bueno, nunca se sabe si mañana Microsoft decide dejar de soportarlo en los próximos directx
y obviamente las tarjetas graficas nuevas ni se molestarán mucho en darle apoyo hardware especifico. asi que renovarse o morir, aunque sea para simular 2d en un entorno 3d... (y en mi caso es peor, porque simulo 3d sobre 2d simulado en 3d
:P )
Título: Optimizar Direct3d Para 2d
Publicado por: TheAzazel en 29 de Octubre de 2005, 11:39:30 AM
 @kachorro, y lo de pasarlo todo a opengl... es sencillo tal y como lo has creado? que luego eso da muchos quebraderos de melon....
Título: Optimizar Direct3d Para 2d
Publicado por: KACHORRO en 29 de Octubre de 2005, 02:32:16 PM
 Si ya lo tengo pasado , a Direct3D, pero de la misma forma lo pasé a OpenGL

simplemente hay que cambiar la capa gráfica del motor isométrico. Qué no es gran cosa, con un putsprite y poco más se hacen grandes cosas.

Título: Optimizar Direct3d Para 2d
Publicado por: Ray en 29 de Octubre de 2005, 03:33:37 PM
 Si usas opengl hay una forma eficiente de guardar y renderizar posteriormente la informacíon de los estados, primitivas, etc.  Con listas de presentación.

Así es su uso.


GLuint Arbol;
glNewList( Arbol=glGenLists(1), GL_COMPILE);

/*
aqui establecemos la textura, mezclas, primitivas, y cualquier tipo de operación necesaria para dibujar el sprite, objeto 3d, o combinaciones de estos, sin importar el número de cálculos o funciones propias que usemos para ello. Nos despreocupamos.
*/

glEndList();

En la lista queda guardada solo la información necesaria y optimizada para ser enviada a la tarjeta gráfica cuando queramos dibujar.  Lógicamente cuantos menos hayan más rápido irá, por lo que siempre es mejor hacer grupos que usen la misma textura.

Con glTranslate le decimos donde queremos situarlo antes de llamar a la lista.


glTranslatef(200.0, 20.0, 0.0);
glCallList(Arbol);

glTranslatef(100.0, 50.0, 0.0);
glCallList(Arbol);
...


Me gusta OpenGL  B)