Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Dibujar una imagen grande con DirectX

Iniciado por bnl, 08 de Octubre de 2006, 04:34:20 PM

« anterior - próximo »

bnl

Quiero dibujar con DirectX 9.0 un fragmento de 800x600 de una gran imagen que podria tener un tamaño de 800x600 o superior (hasta 5000x2000)

¿Cual pensais que es la mejor forma de hacerlo? ¿Usando dos triangulos enormes y poniendoles la textura? ¿Utilizando un sprite? ¿de alguna otra forma?

¿Y para imagenes de menor tamaño (50x50 o similares)?
Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

senior wapo

Un quad (2 tris) con la textura. Asegurate de que la tarjeta puede usar texturas tan grandes o te tocara partirla.

Si quieres que funcione en tarjetas Vodoo3 o inferior, texturas de 256x256 maximo. Si te da igual, 512x512 te pilla la mayoria de las otras tarjetas moderadamente viejas.

Tendras que dividir la textura grande en quads mas pequeños de la misma forma que combinas varios lightmaps en una textura. Googlea "texture atlas" para ver una idea.

La ventaja la tienes en que no combinas imagenes al azar sino que sabes que son piezas de una misma imagen original de tamaño conocido.


O alternativamente... pasar de compatibilidades viejas y usar una textura solo (soporte 1024x1024 no es tan raro).


Para los sprites, lo que he dicho antes: texture atlas (todos os fotogramas de animación en la misma textura).

bnl

No comente en el post que era para dibujar en 2D. Seria para dibujar el fondo.

No me ha quedado claro si para dibujar la imagen me recomiendas que use 2 triangulos o un sprite llamando al metodo draw o draw2D.

Tengo entendido q las texturas deben ser potencia de 2. ¿Deberia entonces aumentar la imagen para que sus dimensiones fueran potencia de 2 y rellenar el nuevo espacio con cualquier color?
Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

senior wapo

Eso es lo que pensaba, que era para pintar el fondo.

Yo utilizo triángulos para todo, pero porque mi librería tiene que ser compatible con varias versiones de DX y OGL.

Las texturas en algunas tarjetas no han de ser cuadradas ni potencia de 2, y en otras sí. Yo le que te decía es partir el rectángulo en cuadraditos más pequeños, potencia de 2, usando varios quads.

Ejemplo partiendo en bloques de 512x512:



Como el fondo sólo lo pintas una vez por fotograma puedes permitirte el subir unos pocos vértices extras a la tarjeta.

Pero como ya te dije en el post anterior, ésto es como prefiero yo porque tengo interés en compatibilidad con las tarjetas viejas. No es una necesidad con las tarjetas de hoy en día, simplemente un ahorro opcional de ancho de banda si la tarjeta te obliga  a subir texturas cuadradas (800x800 que en realidad sería 1024x1024 en este ejemplo).

Tu decides.


EDIT: Ahora que releo lo de 5000x2000, simplemente particiona en tiles de 256x256 y vuelca los que sean visibles a la pantalla. Habia asumido que la imagen la volcabas completa y del tamaño justo de pantalla.

bnl

Gracias por tus respuestas.

Entonces descarto el uso de un sprite. Aunque con el sprite es mas sencillo porque no tienes q crearte los vertices.

Para que funcione en el mayor numero de tarjetas entonces utilizaré texturas cuadradas y de tamaño que sea potencia de 2, concretamente de 256.
Tambien implementare lo que comentas del texture atlas.
Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

ethernet

Pero normalmente se hace un atlas de texturas para dibujar varios objetos o lo que sea (p ej, ligthmaps) sin necesidad de cambiar de contexto y ahorrarte la parada de la tarjeta.

bnl

Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

ethernet

Con contexto me refiero a tener que cambiar la textura o el shader activo, por ejemplo. Normalmente cuando mandas a renderizar una escena los objetos suelen ir ordenados por material para no tener que cambiar de contexto muchas veces, esto es, renderizar todos los objetos con el mismo material seguidos.

SpeedTree aprovecha esta técnica hasta el extremo.

[EX3]

Yo sinceramente no me complico mucho la vida en este tema. Con la dx_lib32 y tomando como valor por defecto 1024x1024 como valor compatible por la mayoria de las tarjetas actuales, para un fondo de 800x600, como el que utilizaba la pantalla de carga en la prueba que subi en este post, suelo cargar la imagen tal cual, aun a sabiendas de que se reescalara a 1024x1024 o un maximo inferior de la tarjeta segun modelo (512x512) y en el caso de que sea 1024x1024 no pierde apenas calidad la textura al pintarla a 800x600. El resultado es un comodo suavizado de pixeles, que para un fondo no queda mal.

Sinceramente, a no ser que necesites una calidad exacta al original, y que no requieras ejecutar tu programa en tarjetas demasiado antiguas, yo no me andaria con lios de particionar en texturas pequeñas la imagen, aunque no niego que dicha tecnica es interesante para otros propositos.

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

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

senior wapo

Cita de: "ethernet"Pero normalmente se hace un atlas de texturas para dibujar varios objetos o lo que sea (p ej, ligthmaps) sin necesidad de cambiar de contexto y ahorrarte la parada de la tarjeta.


El cambio de textura es inevitable si el fondo no cabe en la textura máxima y no quieres perder calidad usando una imagen más pequeña.

Si la tarjeta soporta un tamaño más grande te toca hacer profiling de tu arquitectura objetivo y decidir:
- Si renta más subir una textura de 1024x1024 aunque desperdicies pixeles por un lado y por abajo (224 y 424 en este caso). Menos cambios de estado pero subes más datos y requieres mas espacio contiguo disponible en la VRAM.
. Si conviene más subir 2 texturas de 512 que desperdicien menos pixeles (menos ancho de banda) pero provocan cambio de textura.

Si domina el tiempo de cambio de textura (sobrecarga del API, reset de tablas internas del driver, cache trashing en la GPU/driver, stalls, etc...) puede compensar más subir una grande. En cambio si la transferencia a la tarjeta es lenta, o te supone tirar fuera de la VRAM otras texturas que podrias haber reutilizado luego, pues te renta más partir en dos. Profile, profile :D

En mi ATI9600 con 128MB con texturas grandes, pues lo subiría a capón ya que de un fotograma al siguiente de un juego casual no lleno 128MB ente todas las texturas ni loco. En la RAGE4MB de mi otro portatil, aunque cabe (1024x1024) me como toda la memoria disponible y todas las otras texturas las tira fuera y toca volver a subirlas al empezar el siguiente fotograma (todo serán fallos de cache).
Y eso a 800x600 de resolución de pantalla 16 bits, que a más tamaño directamente ni cabe entera porque el zbuffer y el secondary buffer no dejan hueco.
En una consola portátil, super móvil, o PDA a saber...

Todo esto por rizar el rizo y tenerlo todo, porque siempre puedes simplificar como dice [Ex3] y el que no tenga bastante máquina que se compre una nueva o pierda calidad :P

marcode

Cita de: "bnl"Quiero dibujar con DirectX 9.0 un fragmento de 800x600 de una gran imagen que podria tener un tamaño de 800x600 o superior (hasta 5000x2000)
Si el cálculo que he hecho no me falla, como máximo ocupara 28 Mb, que residiendo en memoria de vídeo no tendrás el mínimo problema de velocidad.

Cita de: "bnl"
¿Cual pensais que es la mejor forma de hacerlo? ¿Usando dos triangulos enormes y poniendoles la textura? ¿Utilizando un sprite? ¿de alguna otra forma?
Sí, lo de partir la imagen en texturas de 512 como ha dicho Senior Wapo (me parece ideal ese tamaño para construir el fondo), yo creo también que es lo mejor. No es imprescindible que sean potencia de 2 en Directx pero sí es muy recomendable.

Tal vez así:

1. Crear el número de texturas 512x512 necesario para abarcar toda la imagen y copiar el bloque correspondiente en cada una de ellas.

2. Crear una malla de quads también de 512x512 de tamaño, una por cada textura, en su fila y columna correspondiente (determinado por su posición x,y absoluto en el mapa).

3. Desplazar o situar la malla de quads modificando la matriz modelview (o la propia cámara) para ver la zona elegida.

4. Comprobar cada quad si es visible, si lo es se dibuja con su textura correspondiente, si no.. no se dibuja nada (o se puede pintar con un color o en modo wireframe).

Hay más formas de hacerlo seguramente, pero esta va como un tiro seguro.

Cita de: "bnl"
¿Y para imagenes de menor tamaño (50x50 o similares)?

Yo creo que para eso lo mejor es agruparlas en texturas también de 512x o 1024x y crear una clase Sprite donde entre otras cosas (estados, posición, rotación, efectos, etc. ) se guarde un apuntador a la textura usada, y la posición y tamaño que ocupa dentro de ella, y dibujarla también con un Quad con las coordenadas de textura correspondientes.

Me alegra ver que la gente usa DirectX para hacer cosas pequeñas, hay que desterrar el mito de que solo sirve para hacer motores 3D.
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]

bnl

CitarMe alegra ver que la gente usa DirectX para hacer cosas pequeñas, hay que desterrar el mito de que solo sirve para hacer motores 3D.

Como q cosas pequeñas!!! Estoy haciendo un mega motor 3D  :D

Que va, será todo en 2D

¿Para montar todo lo de dividir la imagen en fragmentos, deberia dividir la imagen en tiempo de ejecucion o guardar ya las imagenes de 512x512?
Si es dividiendo las imagenes en varios ficheros deberia guardar tambien en otro fichero la informacion para poder luego montar la imagen completa, para saber que fragmento va en que sitio.
Mi web: http://www.brausoft.com/
No sabían que era imposible, así que lo hicieron.

marcode

Yo creo que mejor crear las texturas con su fragmento correspondiente (que residiran en la memoria de vídeo) copiando los datos de la imagen total, que lo normal es que esté en memoria de sistema porque lo habrás descomprimido de un archivo en disco, que despues podrás liberar si no es necesario, una vez creadas las texturas.

También puedes hacer lo que dices de guardar cada fragmento en cada fichero y nombrarlo por fila-columna ej: FondoEspacial_7_3.mpg

Despues sabes que cada textura/quad va en una coordenada diferente multiplo de su tamaño, por ejemplo el del ejemplo sería X=3*512, Y=7*512, osea...   1536, 3584 como coordenada absoluta (de la esquina de arriba a la izquierda).

Dependiendo de la posición de la cámara obtendrás su posición relativa en la pantalla, si alguna parte del quad cae dentro se dibuja, si no, se evita dibujar.

Yo creo que haría una clase para manejar cada trozo, que contenga la textura, tamaño, su posición en fila/columna, y sus métodos de carga (si son archivos independientes), comprobación y dibujado correspondientes. Pero insito que hay más formas de poder hacerse.
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]






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.