OpenGL - Erkennung von Kanten

11

Ich möchte beliebige Netze laden und dicke schwarze Linien entlang der Kanten zeichnen, um ein Toon-Shading-ähnliches Aussehen zu erhalten. Mit dem Schablonenpuffer konnte ich eine schwarze Silhouette um die Objekte zeichnen. Sie können das Ergebnis hier sehen:

Geben Sie hier die Bildbeschreibung ein

Was jedoch fehlt, sind die schwarzen Linien im Objekt selbst. Ich dachte darüber nach, normale Diskontinuitäten zu überprüfen: Überprüfen, ob ein benachbartes Pixel einen anderen normalen Vektor als das aktuelle hat. Wenn ja, wurde eine Kante gefunden. Leider habe ich keine Ahnung, wie ich diesen Ansatz implementieren könnte, weder in OpenGL noch in GLSL Vertex / Fragment Shader.

Ich würde mich sehr über Hilfe bei diesem oder einem anderen Ansatz zur Kantenerkennung freuen.

Bearbeiten: Ich verwende keine Texturen für meine Netze.

Genauer gesagt möchte ich eine CAD / CAM-Lösung erstellen, die so gut wie möglich aussieht (entnommen aus Top Solid https://www.youtube.com/watch?v=-qTJZtYUDB4 ):

Geben Sie hier die Bildbeschreibung ein

enne87
quelle
Ich glaube, Sie müssen die "Kante" detaillierter definieren. Wie unterscheidet es sich von einem einfachen Drahtmodell? In der cifz-Antwort gibt es eine gute Beschreibung des Nachbearbeitungsprozesses auf dem Bildschirm, aber anhand Ihrer Frage ist es schwierig festzustellen, ob er anwendbar ist.
Andreas
Nun, mit Kante meine ich die "Falten" und "Grate", die die Feststoffe bilden. Ein Drahtmodell würde alle Dreiecksflächen anzeigen, was ich nicht möchte.
enne87
Ok, genau das, wonach ich gefragt habe :-) Ich würde aus diesen Falten und Graten ein Drahtmodell erzeugen. Der schwierige Teil ist immer noch zu bestimmen, was eine Falte / ein Kamm ist. Haben Sie eine Idee, wie das geht?
Andreas
1
Die CAD-Programme tun dies meistens nicht mit einem Shader. Stattdessen kennen sie die harten Kanten des Modells und zeichnen eine Linie über das Netz, die diese Informationen enthält.
Joojaa
joojaa hast du noch mehr informationen zu dieser technik? Was ist bei doppelt gekrümmten Freiformflächen zu tun? Ich bin mir auch nicht sicher, was passiert, wenn Sie einen Kegel oder einen Zylinder haben, der von etwas Freier geschnitten / getrimmt wird. stackoverflow.com/questions/43795262/…
Dusan Bosnjak 'Pailhead'

Antworten:

17

Im Allgemeinen läuft die Kantenerkennung darauf hinaus, Bereiche des Bildes mit hohem Gradientenwert zu erkennen.

In unserem Fall können wir den Gradienten grob als Ableitung der Bildfunktion sehen, daher gibt Ihnen die Größe des Gradienten eine Information darüber, wie stark sich Ihr Bild lokal ändert (in Bezug auf benachbarte Pixel / Texel).
Nun, eine Kante ist, wie Sie sagen, ein Hinweis auf Diskontinuität. Nachdem wir nun den Gradienten definiert haben, ist klar, dass diese Informationen alles sind, was wir brauchen. Sobald wir den Gradienten eines Bildes gefunden haben, müssen wir nur noch einen Schwellenwert darauf anwenden, um einen Binärwert für die Kante / Nichtkante zu erhalten.

Wie findest du diesen Gradienten ist wirklich das, was du fragst und ich muss noch antworten :)

Viele Möglichkeiten! Hier ein paar :)

Eingebaute Shader-Funktionen

Sowohl hlsl als auch glsl bieten abgeleitete Funktionen. In GLSL haben Sie dFdx und dFdy , die Ihnen Gradienteninformationen in x- und y-Richtung geben. Typischerweise werden diese Funktionen in einem Block von 2x2 Fragmenten ausgewertet.
Wenn Sie nicht an einer einzelnen Richtung interessiert sind, ist ein guter Weg, um ein kompaktes Ergebnis zu erzielen , das angibt, wie stark der Gradient in der Region ist, die Breite , die Ihnen nichts anderes als die Summe der absoluten Werte von dFdy und dFdy gibt.
Es ist wahrscheinlich, dass Sie eher an einer Kante des Gesamtbilds als an einem bestimmten Kanal interessiert sind. Daher möchten Sie möglicherweise Ihre Bildfunktion in Luma umwandeln. In diesem Sinne könnte Ihr Shader bei der Kantenerkennung Folgendes enthalten:

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

Bei einem hohen Schwellenwert finden Sie gröbere Kanten, und bei einem niedrigen Schwellenwert können Sie möglicherweise falsche Kanten erkennen. Sie müssen experimentieren, um den Schwellenwert zu finden, der Ihren Anforderungen besser entspricht.

Der Grund, warum diese Funktionen funktionieren, ist erwähnenswert, aber ich habe jetzt keine Zeit dafür. Ich werde diese Antwort wahrscheinlich später aktualisieren :)

Nachbearbeitung des Bildschirmbereichs

Sie könnten schicker sein, jetzt ist das Feld der Kantenerkennung in der Bildverarbeitung immens. Ich könnte Ihnen Dutzende guter Möglichkeiten nennen, um die Kantenerkennung gemäß Ihren Anforderungen zu erkennen, aber lassen Sie es uns vorerst einfach halten. Wenn Sie interessiert sind, kann ich Ihnen weitere Optionen nennen!

Die Idee wäre also ähnlich wie oben, mit dem Unterschied, dass Sie sich eine größere Nachbarschaft ansehen und eine Reihe von Gewichten für umgebende Samples verwenden könnten, wenn Sie möchten. Normalerweise führen Sie eine Faltung über Ihr Bild mit einem Kernel durch, der Ihnen als Ergebnis gute Verlaufsinformationen liefert.
Eine sehr häufige Wahl ist der Sobel-Kernel

                                   Geben Sie hier die Bildbeschreibung ein

Welche geben Ihnen Gradienten in x- und y-Richtung:

                                  Aus einem alten PDF habe ich vor langer Zeit geschrieben.

GreindichentM.einGnichtude=(Greindichentx)2+(Greindichenty)2

Dann können Sie wie oben erwähnt einen Schwellenwert festlegen.

Wie Sie sehen können, gibt dieser Kernel dem zentralen Pixel mehr Gewicht, sodass der Gradient + ein wenig Glättung effektiv berechnet werden, was traditionell hilfreich ist (häufig ist das Bild Gaußsch verschwommen, um kleine Kanten zu beseitigen).

Das obige funktioniert ganz gut, aber wenn Sie die Glättung nicht mögen, können Sie die Prewitt-Kernel verwenden:

                                                   Geben Sie hier die Bildbeschreibung ein

(Beachten Sie, dass ich in Eile bin und bald richtig formatierten Text anstelle von Bildern schreiben werde!)

Wirklich, es gibt viel mehr Kernel und Techniken, um die Kantenerkennung auf bildprozessähnliche Weise zu finden, als Echtzeitgrafiken. Daher habe ich kompliziertere (Wortspiel nicht beabsichtigte) Methoden ausgeschlossen, da Sie mit dFdx / y-Funktionen wahrscheinlich in Ordnung wären .

cifz
quelle
Sehr schöne Erklärung cifz, aber was ist, wenn in einer bestimmten Situation kein Farbverlauf sichtbar ist? Zum Beispiel gibt es keine Lichtquelle auf der Rückseite des Würfels und daher ist kein Gradient sichtbar. Dann würde dieser von Ihnen beschriebene bildbasierte Kantenerkennungsprozess nicht funktionieren, oder?
enne87
Wenn Sie einen verzögerten Renderer verwenden, können Sie dasselbe tun, jedoch auf dem normalen Puffer oder erneut, wenn Sie eine Vorüberprüfung haben, können Sie den Algorithmus auf die Tiefe anwenden. Trotzdem haben Sie Recht, ein Bildschirmansatz ist möglicherweise nicht in allen Fällen ideal :) Welche Lösung realisierbar ist, hängt stark davon ab, wie hoch Ihr Budget für diesen Effekt ist und wie komplex Ihre Szene ist.
Cifz
Wenn dies für Ihr Spiel wirklich von zentraler Bedeutung ist, besteht eine sehr einfache, aber möglicherweise anstrengende Möglichkeit darin, für jeden Scheitelpunkt (offline beim Laden) einen Gradienten für Ihre benachbarten Normalen zu berechnen und diesen Faktor als zusätzliches Scheitelpunktattribut zu übergeben.
Cifz
Thangs nochmal cifz für deine Hilfe. Nun, was ich erreichen möchte, ist die Entwicklung einer CAD / CAM-Lösung, die ungefähr so ​​aussieht: youtube.com/watch?v=-qTJZtYUDB4 Und ich würde wirklich gerne wissen, wie sie es geschafft haben, alle schwarzen Kanten und Falten zu rendern und Grate. cifz, denkst du als Grafikprogrammierer, dass sie diesen Look mit einem deiner Screen-Space-Ansätze erzielt haben? Oder vielleicht durch Berechnung eines Gradienten auf benachbarten Normalen? Ich möchte wirklich wissen, wie das gemacht werden kann. Danke noch einmal!
enne87
1
Sie müssen niemanden bezahlen, lesen Sie einfach ein paar Tutorials online, kaufen Sie ein paar Bücher und lernen Sie hart :) Am Ende wird es sehr lohnend sein!
Cifz
3

Nur für den Fall, dass jemand auch Kanten erkennen muss: Hier ist ein schöner Artikel zum Anzeigen eines Drahtgitters und in diesem Artikel wird erklärt, wie nur die Kanten angezeigt werden.

enne87
quelle