Juegos en 2D y OpenGL moderno

10

Preconceptos

Ok, entonces lo que he reunido hasta ahora es esto:

  • no use tubería fija (en desuso o va a estar en desuso)
  • vbos almacena "modelos de objetos" (n datos de vértices, principalmente)
  • los vaos describen cómo se establecen los datos para que las llamadas de sorteo sepan qué parte de cada vbo es para qué tipo de información de vértice (un vao puede referirse a múltiples vbos, lo contrario es un poco difícil)
  • cada llamada de sorteo también envía datos de vértices a sombreadores

Cómo veo 3D (opcional)

Dada esta información, puedo ver cómo dibujar objetos complicados en 3D es muy agradable con OpenGL moderno. Básicamente, carga un montón de modelos de objetos (probablemente de Blender u otro software similar) en VBO con coordenadas locales, y luego simplemente proporciona para cada instancia de un objeto un parámetro de sombreado diferente (desplazamiento) para dibujar en el espacio mundial.

Problema / pregunta

Sin embargo, en 2D los problemas y las prioridades son completamente diferentes. No dibuja objetos muy complejos, no necesita matrices de proyección complicadas y los sombreadores son mucho más simples.

¿Cuál sería la mejor manera de dibujar geometría cambiante con frecuencia (realmente con frecuencia, básicamente cada cuadro) con OpenGL moderno?

En el siguiente párrafo puede ver algunas ideas de problemas (el problema del círculo y el rectángulo), que identifican mejor el tipo de cambios que me interesan.

Mis intentos (opcional)

Entonces, comencé a pensar cómo lidiaría con el dibujo de geometría 2D básica en la pantalla:

  • un cuadrado: cargue un [(1, 0), (1, 1), (0, 1), (0, 0)]VBO para la geometría de un cuadrado en el espacio local, luego proporcione al sombreador el ancho real de las coordenadas del cuadrado y del mundo e información de color

se enfría, se ve fácil. Pasemos a un círculo:

  • un círculo: abanico triangular con ... eh. ¿Cuánta precisión (número de vértices)? para círculos pequeños, la precisión debe ser pequeña y para los círculos con errores, la precisión debe ser alta. Claramente, cargar 1 VBO no puede adaptarse a todos los casos. ¿Qué sucede si necesito agregar precisión porque un círculo cambia de tamaño para ser más grande?

Menos genial Pasemos a algo un poco más fácil, un rectángulo:

  • un rectángulo: eh. no hay "geometría de rectángulo general". Solo tiene una proporción ancho / alto y eso es todo, pero cada rectángulo es probablemente diferente si el tamaño cambia.

Como puede ver, las cosas van cuesta abajo desde allí. Especialmente con polígonos complejos y demás.

Sin política de código: P

Solo necesito una descripción general de la idea, no es necesario ningún código, especialmente el código C o C ++. Simplemente diga cosas como: "haga un VBO con estos datos de vértice, y luego agréguelo, ...".

Zapato
fuente
Creo que entiendo lo que está preguntando, pero es posible que desee dar a esta pregunta un poco más de dirección. No está claro qué se pregunta, lo que en realidad es una razón cercana.
Lysol
@AidanMueller No estoy seguro de lo que quieres decir, pero siéntete libre de dar más dirección si sientes la necesidad.
Zapato
La respuesta principal actualmente comienza diciendo "Tu pregunta principal parece ser". Eso indica que no está claro lo que está preguntando. Tal vez debería dar un resumen de lo que no necesita saber al final de su pregunta. Esto es un Q / A después de todo, no una discusión.
Lysol
@AidanMueller No en ese contexto, creo. Dice "Su pregunta principal parece ser ..." y luego cita la pregunta que publiqué. Lo que en realidad indica que es lo suficientemente claro como para ser citado. Además, la frase no indica que mi pregunta no sea clara, sino que hay una pregunta principal y otra pregunta secundaria (que es: ¿cuál es la solución a los casos específicos que he presentado?). Realmente no veo el problema con mi pregunta actual, y aparentemente ni siquiera los que respondieron lo hicieron, ya que encontré ambas respuestas muy útiles y al punto.
Zapato
Puede dibujar un círculo preciso con un sombreador de fragmentos.
user253751

Respuestas:

5

Su pregunta principal parece ser:

¿Cuál sería la mejor manera de dibujar geometría cambiante con frecuencia (realmente con frecuencia, básicamente cada cuadro) con OpenGL moderno?

En la mayoría de los casos, no hay una gran diferencia entre 2d y 3d OpenGL. La canalización de gráficos tiene esa coordenada adicional, Z, que no se usará tanto en 2d, pero eso es todo.

Hay algunas formas de cambiar la geometría en cada dibujo.

  • Puede empujar nuevos vértices proporcionados por la CPU en cada cuadro. (Consulte /programming/14155615/opengl-updating-vertex-buffer-with-glbufferdata para obtener algunas notas sobre la reutilización de buffers).

  • Puede dibujar diferentes partes de un búfer existente, con glDrawArrays(mode, first, count). Si la animación se repite, tal vez pueda colocar los cuadros precalculados con las diferentes listas de vértices en un búfer grande, y dibujar la porción apropiada del búfer en cada cuadro.

  • Puede influir en la lista de vértices con otros datos, como una matriz uniforme o una textura. En su sombreador de vértices, lea estos datos y aplíquelos adecuadamente. Estos son solo otros modismos para presentar datos a la GPU, y probablemente no tendrán mucha diferencia en el rendimiento.

  • Si tiene muchas instancias de la misma geometría (posiblemente influenciadas por atributos), entonces glDrawElementsInstanced()puede ser útil

  • Puede influir algorítmicamente en la lista de vértices en los sombreadores de vértice, geometría o teselación. Si la animación se puede describir matemáticamente, es posible que pueda mantener la misma lista de vértices y cambiar solo algunos uniformes de sombreado en cada cuadro.

Y tal vez su animación podría expresarse como texturas puras, con toda la animación hecha píxel por píxel por la CPU, o renderizada previamente desde el disco.

En general, yo diría: "Las computadoras son rápidas, hacen que funcione de la manera más fácil posible, lo que probablemente sea estableciendo nuevos vértices hechos por CPU en cada cuadro. Luego, vea si eso es lo suficientemente bueno. Perfile el uso de la batería / CPU primero, huella de memoria segundo ".

Su otra pregunta , parafraseada, "¿Cuál es una buena manera de dibujar círculos y rectángulos?"

Círculos

  • Con los sombreadores de teselación (o sombreadores de geometría) puede hacer que su geometría sea dinámica.

  • Puede dibujar cuadrados, y en su sombreador de fragmentos solo opaco (alfa = 1.0) dentro de un radio y transparente (alfa = 0.0) fuera del radio. Entonces es píxel perfecto cada vez. (Haga sus vértices cuadrados de -1 a +1, y en el sombreador de fragmentos algo así como outColor.a = dot(coord.xy, coord.xy) < 1.0 ? 1.0 : 0.0;. También podría suavizar un poco el borde, se vería bien allí ...)

  • Siempre puedes usar, por ejemplo, un ventilador de 120 triángulos. Probablemente lo suficientemente bueno.

Rectángulos

  • Creo que respondiste tu propia pregunta sobre esa. ¡Lo que sugieras funcionará bien!
David Van Brink
fuente
El fragment-shader / radio es bastante ordenado, gracias. Con respecto a mí respondiendo mi propia pregunta, no creo entender lo que quieres decir.
Zapato
Oh, al igual que con un cuadrado, mencionas controlar el ancho (con uniforme, supongo), y escribiste: "Solo tienes una proporción ancho / alto y eso es todo, pero cada rectángulo es probablemente diferente si el tamaño cambia". . Entonces, para un rectángulo, haga lo mismo que un cuadrado, pero necesitará 4 valores (x, y, w, h) en lugar de 3 (x, y, w). O pasar (xlow, xhigh, ylow, yhigh) como cuatro uniformes. Con su entrada (0,0) a (1,1), eso es suficiente para que el Vertex Shader haga lo que necesita.
David Van Brink
Oh, ya veo, eso tiene sentido.
Zapato
¿Hay un ventilador automático en GL moderno como GL_TRIANGLE_FAN de la tubería de función fija?
John P
5

No puedo decir que sea un experto en este tema, y ​​en mi (s) proyecto (s) de juego me he concentrado más en el lado 3D, por lo que mi lado 2D es bastante simple en general, usando cosas hechas para el lado 3D; y, obviamente, mi perspectiva está en el lado de los juegos, por lo que mis gráficos 2D tienen más que ver con los sprites que con la geometría. Desde esa perspectiva,

1) Los cuadrados y rectángulos son bastante fáciles. Solo tengo una sola caja 1x1 en un VBO que utilizo para borrar todo. Paso matrices MVP al sombreador con este "cuadro de unidad", y lo he combinado con una escala adicional para escalar el cuadro a las dimensiones correctas, como saben, puede tener diferentes escalas x e y.

Para mis propósitos, he estado pensando en pasar del uso de "caja de unidad" a algún tipo de motor de partículas para destruir sprites 2D, pero esa es otra historia.

2) No he trabajado mucho con círculos, solo uso VBO fijos con un número específico de vértices. Pero podría imaginar que podría hacer algunos ajustes de zancada para afectar la cantidad de vértices dibujados para el círculo.

Cuando conecto datos VBO a atributos de sombreador, uso glVertexAttribPointer. Tiene un parámetro stride destinado a ser utilizado para datos intercalados (que yo uso). Pero podría ser posible usarlo así:

glVertexAttribPointer(..., n * sizeof(VERTEX_DATA), ...);

... para elegir cada enésimo vértice del búfer, lo que afecta al número de vértices dibujados para el círculo. Podría crear varios VAO que tengan el mismo VBO con un paso diferente que afecte al número de vértices dibujados para el círculo. No lo he intentado, pensó.

En general, sí, trabajar con VBO y hacer que el ajuste del lado de la CPU sea un poco más complejo, por eso he estado estudiando diferentes cosas para hacer ajustes en el lado de la GPU (sombreadores). Aún así, según este artículo, el uso de VBO es más eficiente en el hardware moderno, incluso si necesita mucha "intervención" del lado de la CPU:

http://www.quelsolaar.com/opengl_performance.txt

Espero que esto te ayude un poco a diseñar y decidir tus direcciones.

MaKo
fuente
2
"ajustes de zancada para afectar la cantidad de vértices dibujados para el círculo" ¡Súper genial!
David Van Brink