opengl - ¿Cómo renderizo líneas 2D gruesas como polígonos?
path geometry (9)
Tengo un camino compuesto por una lista de puntos 2D. Quiero convertirlos en una tira de triángulos para renderizar una línea texturizada con un grosor específico (y otras cosas similares). Así que, esencialmente, la lista de puntos 2D debe convertirse en una lista de vértices que especifique el contorno de un polígono que, si se representa, representará la línea. El problema es manejar las uniones de esquina, mitras, gorras, etc. El polígono resultante debe ser "perfecto" en el sentido de que no haya sobregiro, juntas limpias, etc. para que pueda ser extruido o manipulado.
¿Hay algún recurso simple que pueda proporcionar información sobre algoritmos, código o más información sobre cómo hacerlo de manera eficiente?
Absolutamente NO QUIERO una biblioteca de vectores bidimensionales completa (cairo, antigrain, OpenVG, etc.) con curvas, arcos, guiones y todas las campanas y silbatos. He estado investigando en varios árboles fuente para implementaciones OpenVG y otras cosas para encontrar algo de información, pero todo es terriblemente intrincado.
Definitivamente estoy dispuesto a codificarlo solo, pero hay muchos casos degenerados (segmentos pequeños + anchuras gruesas + esquinas agudas) que crean todo tipo de problemas de unión. Incluso un poco de ayuda me ahorraría horas tratando de lidiar con todos ellos.
EDITAR: Aquí hay un ejemplo de uno de esos casos degenerados que causa fealdad si fueras simplemente a ir de vértice a vértice. Rojo es el camino original. Los bloques de color naranja son rectángulos dibujados en un ancho específico alineado y centrado en cada segmento.
A partir de su imagen, parece que está dibujando un recuadro alrededor de los segmentos de línea con FILL on y utilizando color naranja. Si lo hace, seguro que creará malos sobregiros. Entonces, lo primero que debe hacer es no hacer un borde negro y el color de relleno puede ser opaco.
¿Por qué no puedes usar la primitiva GL_LINES para hacer lo que intentas hacer? Puede especificar el ancho, el filtrado, la suavidad y cualquier textura. Puedes renderizar todos los vértices usando glDrawArrays (). Sé que esto no es algo que tengas en mente, pero como te estás enfocando en el dibujo en 2D, este podría ser un enfoque más fácil. (buscar Líneas texturadas, etc.)
Acabo de encontrar este trabajo increíble:
http://www.codeproject.com/Articles/226569/Drawing-polylines-by-tessellation
Parece hacer exactamente lo que quiere, y su licencia permite usarlo incluso en aplicaciones comerciales. Además, el autor hizo un gran trabajo al detallar su método. Probablemente le daré una oportunidad en algún momento para reemplazar mi propia implementación no tan perfecta.
Creo que buscaría un algoritmo de teselación. Es cierto que en la mayoría de los casos en que se usan, el objetivo es reducir el número de vértices para optimizar el renderizado, pero en su caso se puede parametrizar para conservar todos los detalles, y la posibilidad de optimización puede ser útil.
Existen numerosos algoritmos de teselación y códigos en la Web; envolví una C pura en una DLL hace unos años para usarla con un renderizador de paisajes Delphi, y no son un tema poco común para tutoriales de codificación de gráficos avanzados y similares.
En mi caso, podría darme el lujo de sobregirar. Acabo de drow círculos con radio = ancho / 2 centrado en cada uno de los vértices de la polilínea.
Los artefactos están enmascarados de esta manera, y es muy fácil de implementar, si puedes vivir con esquinas "redondeadas" y algunos sobregiros.
Oh, bueno, intenté resolver ese problema yo mismo. Perdí dos meses en una solución que intentó resolver el problema del sobregiro cero. Como ya ha descubierto, no puede tratar todos los casos degenerados y no tiene sobregiro cero al mismo tiempo.
Sin embargo, puede utilizar un enfoque híbrido:
Escríbase una rutina que verifique si las uniones pueden construirse a partir de geometría simple sin problemas. Para hacerlo, debe verificar el ángulo de unión, el ancho de la línea y la longitud de los segmentos de línea unidos (los segmentos de línea que son más cortos que su ancho son un PITA). Con algunas heurísticas deberías ser capaz de resolver todos los casos triviales.
No sé cómo se vería su línea de datos promedio, pero en mi caso más del 90% de las líneas anchas no tenían casos degenerados.
Para todas las demás líneas:
Probablemente ya hayas descubierto que si tolera el sobregiro, generar la geometría es mucho más fácil. Hazlo y deja que un algoritmo CSG de polígono y un algoritmo de tesselación hagan el trabajo difícil.
Evalué la mayoría de los paquetes de teselación disponibles y terminé con el teselador de GLU. Fue rápido, robusto, nunca se estrelló (a diferencia de la mayoría de los otros algoritmos). Era gratis y la licencia me permitió incluirlo en un programa comercial. La calidad y la velocidad de la tesselación están bien. No obtendrá la calidad de triangulación de Delaunay, pero como solo necesita los triángulos para renderizar, eso no es un problema.
Como no me gustaba la API tesselator, levanté el código tesselation de la implementación gratuita de referencia SGI de OpenGL, reescribí todo el front-end y agregué pools de memoria para bajar el número de asignaciones. Tomó dos días para hacer esto, pero valió la pena (como la mejora del rendimiento del factor cinco). La solución terminó en una implementación comercial de OpenVG por cierto :-)
Si está renderizando con OpenGL en una PC, puede mover la tesselation / CSG-job de la CPU a la GPU y usar stencil-buffer o z-buffer tricks para eliminar el sobregiro. Eso es mucho más fácil y puede ser aún más rápido que la teselación de CPU.
También me interesa esto, ya que quiero perfeccionar el trazado de carreteras de mi aplicación cartográfica ( Kosmos ). Una solución que utilicé es dibujar la polilínea dos veces, una con una línea más gruesa y otra con un diluyente, con un color diferente. Pero esto no es realmente un polígono, es solo una manera rápida de simular uno. Vea algunos ejemplos aquí: http://wiki.openstreetmap.org/wiki/Kosmos_Rendering_Help#Rendering_Options
No estoy seguro de si esto es lo que necesitas.
Terminé por ensuciarme las manos y escribir un pequeño lazo para resolver un problema similar.
Para mí, el problema era que quería líneas gruesas en OpenGL que no tuvieran el tipo de artefactos que estaba viendo con OpenGL en el iPhone. Después de mirar varias soluciones; curvas de bezier y cosas por el estilo - decidí que probablemente era más fácil hacer solo el mío. Hay un par de enfoques diferentes.
Un enfoque es encontrar el ángulo de intersección entre dos segmentos y luego moverse a lo largo de esa línea de intersección a cierta distancia de la superficie y tratarlo como un vértice de cinta. Intenté eso y no parecía intuitivo; el ancho de la cinta podría variar.
Otro enfoque es calcular una normal a la superficie de los segmentos de línea y usar eso para calcular el borde de cinta ideal para ese segmento y para realizar pruebas de intersección reales entre segmentos de cinta. Esto funcionó bien, excepto que para las esquinas agudas, las intersecciones del segmento de la línea de cinta estaban demasiado lejos (si el ángulo entre segmentos se acercaba a 180 '').
Trabajé alrededor del problema del ángulo agudo con dos enfoques. El algoritmo de intersección de líneas de Paul Bourke (que utilicé de forma no optimizada) sugirió detectar si la intersección estaba dentro de los segmentos. Como ambos segmentos son idénticos, solo necesitaba probar uno de los segmentos para la intersección. Entonces podría arbitrar cómo resolver esto; ya sea al mezclar el mejor punto entre los dos extremos o al colocar una tapa final - ambos enfoques se ven bien - el enfoque de la tapa final puede desprenderse del polígono frontal / posterior ordenando para opengl.
Ver http://paulbourke.net/geometry/lineline2d/
Ver mi código fuente aquí: https://gist.github.com/1474156
Un método simple fuera de mi cabeza.
Biseca el ángulo de cada Vertex 2d, esto creará una buena línea de inglete. Luego, mueva a lo largo de esa línea, hacia adentro y hacia afuera, la cantidad de su "espesor" (¿o el grosor dividido entre dos?), Ahora tiene sus puntos de polígono interno y externo. Vaya al siguiente punto, repita el mismo proceso, construya sus nuevos puntos de polígono en el camino. A continuación, aplique una triangulación para obtener sus vértices listos para renderizar.
Vea si la triangulación de Delaunay puede ayudar.