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, ...".
Respuestas:
Su pregunta principal parece ser:
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 útilPuede 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
fuente
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í:
... 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.
fuente