Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Efecto "ondas" o "burbuja" en Direct3d

Iniciado por Loover, 19 de Marzo de 2008, 10:54:13 AM

« anterior - próximo »

Loover

Buenas,

No sé si habreis jugado al Aquaria. Para aquellos que sí, lo que me gustaría hacer es un efecto como el que tienen las algas de dicho juego. En él, las algas, aún sin cambiar el sprite (no tienen animación por sprites) ondulan. Parece ser que lo que hace es modificar los vértices del quad en el que están modificadas, para propiciar dicho efecto.

Me gustaría saber cuál es la mejor forma de hacer esto en Direct3d. Lo primero que se me ocurre es lockear el buffer de vértices y modificar a pelo los vértices... pero lockear un buffer constantemente dentro de un loop es muy costoso.

Tampoco creo que en el juego usen vertex shaders para eso, aunque quizás sí, no estoy seguro.

Sea cómo sea, ¿cómo lo haríais vosotros?
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

AK47

Una opción sería hacerlo en plan sistema de particulas: calcular las mallas (que serán muy simples) de todas las algas visiblesen la CPU y hacer un sólo lock/unlock del vertex buffer. No creo que tenga ningún impacto sensible sobre el rendimiento :)

Loover

Sí, eso es lo que me refería. Un solo unlock, modificar vértices, lock.

¿No influiría eso hacerlo para cada bicho de la escena? Imaginemos 100 bichos.
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

Loover

Hey, puedo usar DrawPrimitiveUp, en vez de DrawPrimitive. Así no tendré que hacer ningún lock / unlock.

¿Qué os parece eso?

El problema es que DrawPrimitiveUp es más lenta. Por lo que igual tendré que separar en dos tipos:

- LOV_STATIC_SURFACE     => Uso DrawPrimitive y no se pueden moficicar los vértices
- LOV_DYNAMIC_SURFACE   => Uso DrawPrimitiveUp y sí se pueden modificar los vértices.
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

AK47

Puedes hacer un sólo lock/unlock que agrupe a todos los bichos?

Y DrawPrimitiveUp hace un lock/unlock interno, vamos que no se gana nada

Loover

No creo que me sea posible dicho lock / unlock de todos los bichos. Además que en muchos casos, algunos no cambiarian, solo algunos de ellos...

No sé, tengo que hacer pruebas de rendimiento.
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

[EX3]

Yo hace tiempo me estuve fumando un tutorial del SDK de DirectX para C++ (en el sdk de VB nos marginan en cuestion de tutos "interesantes") donde se implementaban efectos como ondas marinas o efectos "lupa" y recuerdo que tocaban algo a nivel de vertices (vertex shaders quiza...) y bumpmapping si mal no recuerdo (si recuerdo lo enrevesado que son los codigos de los tutos y ejemplos del SDK en ambos lenguajes :P)

Cita de: "Loover"Hey, puedo usar DrawPrimitiveUp, en vez de DrawPrimitive. Así no tendré que hacer ningún lock / unlock.
Interesante, dx_lib32 se apoya en esta funcion para todas las operaciones graficas excepto las de texto y no sabia que se podian hacer efectos de ondas y similares alterando los vertices con dicha funcion.

No estoy muy puesto en el tema y si me iluminarais un poco el asunto seria mucho de agradecer por que hasta ahora daba por sentado que tendria que tirar de pixel shaders para hacer efectos similares al que comenta Loover :)

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

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

Loover

Yo hasta ahora, cuando cargaba una imagen, la recortaba en trozos (del tamaño especificado por el usuario o el tamaño óptimo que consideraba LooverLib) para poder cargar imágenes de cualquier tamaño, (no solo potencia de 2). Creaba un vertexbuffer y en cada frame y para cada sprite, hacia un DrawPrimitive (creía que era más rápido que DrawPrimitiveUp, el cuál solo uso para dibujar las primitivas: líneas, círculos, etc).

Por ejemplo, puedo cargar una imagen de 124x1232 y decirle que me la corte en bloques de 64x64 (está claro que en los bordes ajusto las coordenadas de mapeado porque habrá sobrante).

Ahora bien, si quiero dar la posibilidad de mover los vértices de esos "grids" que creo (cosa que no hacía hasta el momento, pero que es muy interesante para efectos tipo burbuja, etc), tengo varias opciones:

- DrawPrimitive + Unlock / Lock
- DrawPrimitiveUp (con un array propio en el que modifico cuando quiero)
- Vertex Shader

Descartando directamente el Vertex Shader (por que quiero que el engine vaya en tarjetas que no tengan vertex shaders). Me he centrado en leer sobre los dos primeros:

- http://www.gamedev.net/community/forums/topic.asp?topic_id=83590
- http://www.gamedev.net/community/forums/topic.asp?topic_id=314310&whichpage=1&#2016017
- http://www.gamedev.net/community/forums/showfaq.asp?forum_id=10#q28

Pego lo más importante que he deducido:
CitarDan Baker (on the Microsoft Direct3D team) says: "Using DrawPrimUP for very small loads isn't any different then creating a Dynamic Vertex Buffer And filling it yourself - except an extra memcopy (that is negligible since the loads are small). If you are just using it to do UI quads or sprites, then its fine. "

Así que parece ser que si comienzo a usar DrawPrimitiveUp en vez de DrawPrimitive para renderizar mis grids, no voy a notar mucho la diferencia. Otra cosa que me ha dado buena espina, es que tras hablar con un programador del Harvest - Massive Encounter (http://www.oxeyegames.com/harvest/) me han dicho que han usado DrawPrimitiveUp para los sprites. Y ahí tienen MILES de sprites al mismo tiempo.

Como soy un tanto desconfiado, creo que voy a permitir ambos métodos, y hacer unos tests de rendimiento. O quizás no, luego lo decido, conforme vea lo que vais opinando.

También he hablado con Alec, programador del Aquaria, lo que el usa es directamente llamadas a GlQuad(), etc, llamadas directas al Api... cosa que no permite Direct3d.


Un saludo.
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

Prompt

En el caso de que uses vertex shaders, como yo uso en mi motor, es comodisimo hacerse un efecto de tipo ondas, o viento ( para una supercie con plantas ). Está tirao y no hace falta hacer lock / unlock con lo que provoca... en rendimiento. Si tienes el BUS petado de datos por cada frame lo vas a notar.

¿Por qué no puedes hacer lock / unlock de todas las instancias? no las agrupas? no haces "instancing" para renderizar todo lo común a la vez?

Saludos.

Loover

Bueno, antes de renderizar cada sprite, aplico una serie de transformaciones para calcular su rotación, posición, escalado, etc... que son independientes para cada sprite. Y también una transformación del color (puedes hacer entintados, fades, transparencias, etc).

Por lo tanto, si aplico una trasnformación antes de cada sprite, no puedo meterlos dentro de un mismo vertexbuffer. ¿O sí se puede?

Umm, pensandolo bien, debe poderse aplicar la transformación y luego hacer el SetTexture y el DrawPrimitiveUp... pero cada vez que creara un nuevo sprite tendría que agrandar el VertexBuffer "gigante" con todos los sprites y cada ver que borrara un sprite se quedaría un hueco y tendría que copiar zonas del array y ponerlas más atrás... ¿ganaría algo con todo ese tinglado en vez de tener un VertexBuffer por sprite como tengo ahora?

¿Cómo lo haces tú [Ex3]?
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

AK47

Por los vertex shader no te preocupes, si la tarjeta no los acelera lo hace la CPU y con un rendimiento que, obviamente no tan alto como la tarjeta, si suficientemente bueno para usarlo sin problemas.

Y no hagas un DrawPrimitive por cada sprite, agrupalos tanto como puedas, asi la tarjeta tiene mucho mas material para trabajar en vez de estar esperando a la CPU. Es mas rapido calcular todos los vertices de los sprites en la CPU, hacer el lock/unlock y dibujarlos todos a la vez que no hacer ningun lock/unlock y tener que dibujarlos uno a uno

Loover

¿Se ganaría mucho?, porque tal como lo tengo me va muy bien de rendimiento para un gran número de sprites en pantalla.

Estais todos de acuerdo en que ese VertexBuffer gigante con todos los sprites... en el que cada vez que quiero añadir un sprite tendré que redimensionarlo (para añadir el nuevo sprite) y cada vez que quiera borrar uno tendré que copiar todo el array desde la posición en adelante y pegar todo el bloque en la posición donde estaba el sprite... ¿es mejor?

¿Es esto lo que haceis normalmente? ¿Tú también [Ex3] para tus sprites?
IndieLib Libreria 2.5d utilizando aceleración por hardware para la programación de juegos 2d.
Indie Rover The monkeys are reading!

[EX3]

* duplicado *
me voy a cagar en el dichoso "Network error" y su santo padre... dame paciencia para soportar los duplicados, señor ¬¬u
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

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

[EX3]

Cita de: "Loover"- DrawPrimitiveUp (con un array propio en el que modifico cuando quiero)
Parece que no iba tan verde en el asunto como pensaba. Asi es como implemento las trasnformaciones de simulacion de perspectivas 3D en dx_lib32 en la funcion de dibujo en isometrica y caballera, modificando los valores de los vertices del array a pelo :)

Lo que no me queda claro del todo es, yo mis sprites son solo dos triangulos formando un quad, no n quads como usas en looverlib por lo de diseccionar la imagen, quiere eso decir que hace falta varios poligonos para poder simular el efecto de ondas o el numero da igual y con dos puedo meter mano al asunto? (desde mi ignorancia me huele que necesitare mas de dos triangulos :))

Cita de: "Loover"Descartando directamente el Vertex Shader (por que quiero que el engine vaya en tarjetas que no tengan vertex shaders).
A no ser que tengas de target minimo, como yo con la dx_lib32, una GeForce 2 no vas a tener problemas de soporte de Vertex Shader ya que estan presentes desde la GeForce 3 por lo que he leido aqui.

Cita de: "Loover"¿Cómo lo haces tú [Ex3]?
Pues segun se mire... o muy chapuceramente o adaptado al objetivo del render. Me explico. Mi render grafico define un array de profundidad Z para facilitar al programador la ordenacion de dibujado (similara a lo que ofrecia Div Games Studio). Dicho array de profundidad no es mas que una coleccion de arrays, un array por nivel (de 8 a -8 tomando 0 por el nivel intermedio) que almacena los parametros calculados de las operaciones de dibujo que se llaman antes de generar la escena: sprites, primitivas, texto... y poco mas. Este metodo me obliga a individualizar si o si cada objeto sprite/primitiva/texto por separado y no poder agruparlo "facilmente" en un vertexBuffer o similar (tampoco meto la mano en el fuego por no estar muy puesto en el tema de vetexBuffers & cia.). El asunto es que yo genero un quad que luego sera dibujado uno a uno llamando a DrawPrimitiveUp() y dichos quad's se almacenan en un array propio que le paso como parametro a DrawPrimitiveUp(). Mis sprites, como no aplico ningun algorritmo para partir imagenes en fragmentos de potencia de 2 para respetar el aspecto original de una imagen de tamaño irregular (en mi caso se suavizan los pixeles por el autoreescalado de la grafica) solo represento mis sprites como un simple quad de 2 triangulos. Este bajo numero de vertices es lo que me hace dudar que pueda aplicar o no efectos de los mencionados ya.

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

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

AK47

Yo lo que haria sería calcular en cada frame los vertices de todos los sprites, y hacer un lock/unlock de toda esta informacion en un unico vertex buffer. Luego controlas las texturas que tienes que activar y el offset del VB para dibujar cada grupo de sprites. Si es un juego 2D todos estos vertices no seran mucho mas que un par de modelos del quake 3, digo yo, e ira a toda leche. Creo que es asi como se hacen los sistemas de particulas sin recurrir a calculos masivos paralelos con la GPU (cosa que implica pixel shaders y un shader model del 2 parriba creo).

Y repito, los vertex shaders por CPU van mu bien :D






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.