OpenGL - Detección de bordes

12

Me gustaría cargar mallas arbitrarias y dibujar gruesas líneas negras a lo largo de los bordes para obtener un aspecto similar al sombreado de toon. Logré dibujar una silueta negra alrededor de los objetos usando el búfer de plantilla. Puedes ver el resultado aquí:

ingrese la descripción de la imagen aquí

Pero lo que falta son las líneas negras en el objeto mismo. Pensé en verificar las discontinuidades normales: verificar si un píxel vecino tiene un vector normal diferente al actual. En caso afirmativo, se ha encontrado una ventaja. Desafortunadamente, no tengo idea de cómo podría implementar este enfoque, ni en OpenGL ni en el sombreador de vértices / fragmentos GLSL.

Estaría muy feliz de recibir ayuda con respecto a este enfoque o cualquier otro con respecto a la detección de bordes.

Editar: no uso ninguna textura para mis mallas.

Para ser más preciso, me gustaría crear una solución CAD / CAM que se vea lo más posible posible (tomada de Top Solid https://www.youtube.com/watch?v=-qTJZtYUDB4 ):

ingrese la descripción de la imagen aquí

enne87
fuente
Creo que necesita definir el "borde" con más detalle. ¿Cómo se diferencia de una simple estructura metálica? En la respuesta cifz hay una buena descripción del espacio de pantalla posterior al proceso, pero a partir de su pregunta es difícil determinar si es aplicable.
Andreas
Bueno, con borde me refiero a los "pliegues" y "crestas" que forman los sólidos. Una estructura metálica mostraría todas las caras de triángulos, que no es lo que quiero.
enne87
Ok, exactamente lo que pedí :-) Generaría una estructura metálica a partir de esos pliegues y crestas. La parte difícil es determinar qué es un pliegue / cresta. ¿Tienes alguna idea de cómo hacer eso?
Andreas
1
Los programas de cad no hacen esto principalmente con un sombreador. En cambio, conocen los bordes duros del modelo y dibujan una línea en la parte superior de la malla para formar esa información.
joojaa
joojaa ¿tienes más información sobre esta técnica? ¿Qué se hace en caso de superficies de forma libre doblemente curvadas? Tampoco estoy seguro de lo que sucede cuando tienes un cono o un cilindro que está siendo cortado / recortado por algo de forma libre. stackoverflow.com/questions/43795262/…
Dusan Bosnjak 'pailhead'

Respuestas:

18

En general, la detección de bordes se reduce para detectar áreas de la imagen con un alto valor de gradiente.

En nuestro caso, podemos ver crudamente el gradiente como la derivada de la función de imagen, por lo tanto, la magnitud del gradiente le brinda información sobre cuánto cambia su imagen localmente (con respecto a los píxeles / texels vecinos).
Ahora, una ventaja es, como usted dice, una indicación de discontinuidad, por lo que ahora que definimos el gradiente está claro que esta información es todo lo que necesitamos. Una vez que encontramos el gradiente de una imagen, solo es cuestión de aplicarle un umbral para obtener un valor binario borde / no borde.

¿Cómo encuentras que este gradiente es realmente lo que estás preguntando y todavía tengo que responder :)

¡Muchas maneras! Aquí una pareja :)

Construido en funciones de sombreador

Tanto hlsl como glsl ofrecen funciones derivadas. En GLSL tiene dFdx y dFdy que le dan información de gradiente respectivamente en dirección x e y. Normalmente, estas funciones se evalúan en un bloque de fragmentos de 2x2.
A menos que esté interesado en una sola dirección, una buena forma de tener un resultado compacto que indique qué tan fuerte es el gradiente en la región es un ancho que no le da más que la suma del valor absoluto de dFdy y dFdy.
Es probable que esté interesado en una ventaja en la imagen general en lugar de en un canal específico, por lo que es posible que desee transformar su función de imagen en luma. Con esto en mente, cuando se trata de detección de bordes, su sombreador podría incluir algo similar a:

  float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
  float gradient = fwidth(luminance );
  float isEdge = gradient > threshold;

Con un umbral alto, encontrará bordes más gruesos y, por el contrario, puede perder algunos, a la inversa, con un umbral bajo puede detectar bordes falsos. Tienes que experimentar para encontrar el umbral que mejor se adapte a tus necesidades.

Vale la pena mencionar el motivo por el que funcionan estas funciones, pero no tengo tiempo para hacerlo ahora, es probable que actualice esta respuesta más adelante :)

Espacio de pantalla posterior al proceso

Podría ser más elegante que esto, ahora el campo de detección de bordes en el procesamiento de imágenes es inmenso. Podría citarle decenas de buenas maneras de detectar la detección de bordes de acuerdo con sus necesidades, pero hagámoslo simple por ahora, si está interesado, ¡puedo citarle más opciones!

Por lo tanto, la idea sería similar a la anterior, con la diferencia de que podría mirar un vecindario más amplio y usar un conjunto de pesos en muestras circundantes si lo desea. Por lo general, ejecuta una convolución sobre su imagen con un núcleo que le da como resultado una buena información de gradiente.
Una opción muy común es el núcleo Sobel

                                   ingrese la descripción de la imagen aquí

Que respectivamente te dan gradientes en direcciones x e y:

                                  De un viejo pdf que escribí hace mucho tiempo.

GradientMagnitude=(Gradientx)2+(Gradienty)2

Entonces puede umbral como de la misma manera que mencioné anteriormente.

Este núcleo, como puede ver, le da más peso al píxel central, por lo que efectivamente calcula el gradiente + un poco de suavizado que tradicionalmente ayuda (a menudo la imagen es borrosa gaussiana para eliminar pequeños bordes).

Lo anterior funciona bastante bien, pero si no le gusta el suavizado, puede usar los núcleos Prewitt:

                                                   ingrese la descripción de la imagen aquí

(Tenga en cuenta que tengo prisa, ¡pronto escribiré el texto con el formato adecuado en lugar de las imágenes!)

Realmente hay muchos más núcleos y técnicas para encontrar la detección de bordes en un proceso de imagen en lugar de gráficos en tiempo real, por lo que he excluido los métodos más complicados (juego de palabras no intencionado) ya que probablemente estaría bien con las funciones dFdx / y .

cifz
fuente
Muy buena explicación cifz, pero ¿qué pasa si no hay gradiente visible en una determinada situación? Por ejemplo, no hay una fuente de luz en la parte posterior del cubo y, por lo tanto, no hay gradiente visible. Entonces este proceso de detección de bordes basado en imágenes que describas no funcionaría, ¿estoy en lo cierto?
enne87
Si utiliza un renderizador diferido, puede hacer lo mismo, pero en el búfer normal o de nuevo, si tiene un prepago, puede aplicar el algoritmo a la profundidad. Aún así tiene razón, un enfoque de espacio de pantalla podría no ser ideal en todos los casos :) La solución viable depende en gran medida de cuál es su presupuesto para este efecto, qué tan compleja es su escena.
cifz
Potencialmente, si esto es realmente central para su juego, una manera muy fácil, pero potencialmente exigente, sería calcular un gradiente en sus normales vecinas para cada vértice (fuera de línea en el momento de la carga) y pasar este factor como atributo de vértice adicional.
cifz
Thangs nuevamente cifz por su ayuda. Bueno, lo que quiero lograr es desarrollar una solución CAD / CAM que se parezca a esto: youtube.com/watch?v=-qTJZtYUDB4 Y realmente me gustaría saber cómo lo lograron para representar todos los bordes negros, pliegues y crestas. cifz, ¿crees que, como especialistas en programación de gráficos, lograron este aspecto utilizando uno de tus enfoques de espacio de pantalla? ¿O tal vez calculando un gradiente en las normales vecinas? Realmente quiero saber cómo se puede hacer esto. ¡Gracias de nuevo!
enne87
1
No necesita pagarle a nadie, solo comience a leer algunos tutoriales en línea, compre algunos libros y estudie mucho :) ¡Será muy gratificante al final!
cifz
3

En caso de que alguien también necesite detectar bordes: Aquí hay un buen artículo sobre cómo mostrar una estructura metálica y este artículo explica cómo mostrar solo los bordes.

enne87
fuente