Verwenden Sie GL_LINES, um Drahtgitter zu zeichnen
Oxine
Antworten:
367
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
einschalten,
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
wieder normal werden.
Beachten Sie, dass Dinge wie Textur-Mapping und Beleuchtung weiterhin auf die Drahtgitterlinien angewendet werden, wenn sie aktiviert sind, was seltsam aussehen kann.
zwei Anrufe zu tätigen ist überflüssig. benutze GL_FRONT_AND_BACK
shoosh
6
Als Ergänzung zu @ shooshs Kommentar heißt es im Red Book, dass GL_FRONT und GL_BACK veraltet und aus OpenGL 3.1 und höher entfernt wurden. Jetzt können Sie sie weiterhin über die Kompatibilitätserweiterung verwenden. Wenn Sie jedoch zwischen vorwärts- und abwärtskompatibel wählen können, würde ich die erstere empfehlen.
Fouric
1
Der Link in dieser Antwort gibt 404 zurück.
Ondrej Slinták
1
@ OndrejSlinták Es ist jetzt behoben.
MaxiMouse
24
Unter der Annahme eines vorwärtskompatiblen Kontexts in OpenGL 3 und glPolygonModehöher können Sie entweder wie zuvor erwähnt verwenden. Beachten Sie jedoch, dass Linien mit einer Dicke von mehr als 1 Pixel jetzt veraltet sind. Während Sie also Dreiecke als Drahtrahmen zeichnen können, müssen sie sehr dünn sein. In OpenGL ES können Sie GL_LINESmit derselben Einschränkung verwenden.
In OpenGL ist es möglich, Geometrie-Shader zu verwenden, um eingehende Dreiecke aufzunehmen, zu zerlegen und als Quads (wirklich Dreieckspaare) zur Rasterung zu senden, die dicke Linien emulieren. Eigentlich ziemlich einfach, außer dass Geometrie-Shader für schlechte Leistungsskalierung berüchtigt sind.
Stattdessen können Sie Fragment Shader verwenden, was auch in OpenGL ES funktioniert . Denken Sie daran, eine Textur eines Drahtrahmen-Dreiecks auf das Dreieck anzuwenden. Außer dass keine Textur benötigt wird, kann sie prozedural generiert werden. Aber genug geredet, lasst uns codieren. Fragment Shader:
in vec3 v_barycentric;// barycentric coordinate inside the triangle
uniform float f_thickness;// thickness of the rendered linesvoid main(){float f_closest_edge = min(v_barycentric.x,
min(v_barycentric.y, v_barycentric.z));// see to which edge this pixel is the closestfloat f_width = fwidth(f_closest_edge);// calculate derivative (divide f_thickness by this to have the line width constant in screen-space)float f_alpha = smoothstep(f_thickness, f_thickness + f_width, f_closest_edge);// calculate alpha
gl_FragColor = vec4(vec3(.0), f_alpha);}
Und Vertex Shader:
in vec4 v_pos;// position of the vertices
in vec3 v_bc;// barycentric coordinate inside the triangle
out vec3 v_barycentric;// barycentric coordinate inside the triangle
uniform mat4 t_mvp;// modeview-projection matrixvoid main(){
gl_Position = t_mvp * v_pos;
v_barycentric = v_bc;// just pass it on}
Hier sind die Schwerpunktkoordinaten einfach (1, 0, 0), (0, 1, 0)und (0, 0, 1)für die drei Dreiecksspitzen (die Reihenfolge spielt keine Rolle, die in Dreiecksstreifen möglicherweise einfacher macht Verpackung).
Der offensichtliche Nachteil dieses Ansatzes besteht darin, dass einige Texturkoordinaten verbraucht werden und Sie Ihr Scheitelpunktarray ändern müssen. Könnte mit einem sehr einfachen Geometrie-Shader gelöst werden, aber ich würde immer noch vermuten, dass er langsamer ist, als nur die GPU mit mehr Daten zu versorgen.
Ich fand das vielversprechend, aber mit OpenGL 3.2 (Nicht-ES) scheint dies in keiner Weise zu funktionieren. Obwohl es möglich ist, dass ich etwas durcheinander gebracht habe, habe ich einiges damit herumgespielt und bin mir nicht sicher, wie dies überhaupt verwendet werden soll. Weitere Informationen darüber, was Sie mit diesen Shadern tatsächlich rendern möchten, sind hilfreich. Ich sehe nicht, wie etwas anderes als eine Füllung etwas Nützliches hervorbringen würde, aber das funktioniert nicht einmal, da der Alpha-Wert von gl_FragColor in OpenGL 3.2 völlig ignoriert zu sein schien ...
Das Problem, auf das ich stoße, wenn ich versuche, Ihre vorgeschlagene Implementierung zu verwenden, besteht meines Erachtens darin, dass der Shader niemals außerhalb des zu skizzierenden Objekts zeichnet. Dadurch wird der Umriss über das umrissene Objekt gezogen. Mit anderen Worten, der Umriss wird nur in dem zu zeichnenden Originalobjekt enthalten sein.
user1167662
1
@BrunoLevy können Sie zusätzlich in webGL koordiniert bekommen, nein? Wenn Sie Glück haben, können Sie diese Koordinaten möglicherweise von texcoords abrufen, wenn Sie sehr einfache Modelle haben. Andernfalls müssen Sie nur neue Koordinaten hinzufügen. Wäre zu schön, wenn es ohne funktionieren würde :). Sie müssen lediglich einen einzelnen Skalar pro Scheitelpunkt übergeben (und ihn dann im Scheitelpunkt-Shader auf einen 3-Vektor erweitern).
das Schwein
2
Ah, jetzt sehe ich ... f_width () ist in dieser Hinsicht mein Freund. Vielen Dank
Neil Gatenby
5
Wenn Sie die feste Pipeline (OpenGL <3.3) oder das Kompatibilitätsprofil verwenden, das Sie verwenden können
//Turn on wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//Draw the scene with polygons as lines (wireframe)
renderScene();
//Turn off wireframe mode
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
In diesem Fall können Sie die Linienbreite ändern, indem Sie glLineWidth aufrufen
Andernfalls müssen Sie den Polygonmodus in Ihrer Zeichenmethode (glDrawElements, glDrawArrays usw.) ändern, und es kann zu groben Ergebnissen kommen, da Ihre Scheitelpunktdaten für Dreiecke gelten und Sie Linien ausgeben. Für beste Ergebnisse sollten Sie einen Geometrie-Shader verwenden oder neue Daten für das Drahtmodell erstellen.
nicht, wenn es ein Haufen GL_TRIANGLES ist: Sie würden Linien zwischen ihnen bekommen. In OpenGL 1.x oder Legacy verwenden Sie glPolygonMode. In der letzten OpenGL spielen Sie mit dem Geometrie-Shader.
Fabrice NEYRET
Dies ist eine alte Art, Dinge zu tun, die zurückgelassen werden müssen.
Benny Mackney
2
In Modern OpenGL (OpenGL 3.2 und höher) können Sie hierfür einen Geometry Shader verwenden:
#version 330
layout (triangles) in;
layout (line_strip /*for lines, use "points" for points*/, max_vertices=3) out;
in vec2 texcoords_pass[]; //Texcoords from Vertex Shader
in vec3 normals_pass[]; //Normals from Vertex Shader
out vec3 normals; //Normals for Fragment Shader
out vec2 texcoords; //Texcoords for Fragment Shader
void main(void)
{
int i;
for (i = 0; i < gl_in.length(); i++)
{
texcoords=texcoords_pass[i]; //Pass through
normals=normals_pass[i]; //Pass through
gl_Position = gl_in[i].gl_Position; //Pass through
EmitVertex();
}
EndPrimitive();
}
Hinweise:
Für Punkte wechseln Sie layout (line_strip, max_vertices=3) out;zulayout (points, max_vertices=3) out;
Eine gute und einfache Möglichkeit zum Zeichnen von Anti-Alias-Linien auf einem nicht-Anti-Alias-Rendering-Ziel besteht darin, Rechtecke mit einer Breite von 4 Pixel und einer 1x4-Textur mit Alphakanalwerten von {0., 1., 1., 0.} Zu zeichnen. und verwenden Sie die lineare Filterung mit ausgeschaltetem Mip-Mapping. Dadurch werden die Linien 2 Pixel dick, Sie können jedoch die Textur für verschiedene Dicken ändern. Dies ist schneller und einfacher als barymetrische Berechnungen.
Verwenden Sie diese Funktion: void glPolygonMode (GLenum face, GLenum mode);
face: Gibt die Polygone an, für die der Modus gilt. kann GL_FRONT für die Vorderseite des Polygons und GL_BACK für seinen Rücken und GL_FRONT_AND_BACK für beide sein.
Modus: Drei Modi sind definiert und können im Modus angegeben werden:
GL_POINT: Polygonscheitelpunkte, die als Beginn einer Grenzkante markiert sind, werden als Punkte gezeichnet.
GL_LINE: Grenzkanten des Polygons werden als Liniensegmente gezeichnet. (dein Ziel)
GL_FILL: Das Innere des Polygons ist gefüllt.
PS: glPolygonMode steuert die Interpretation von Polygonen für die Rasterung in der Grafikpipeline.
Antworten:
einschalten,
wieder normal werden.
Beachten Sie, dass Dinge wie Textur-Mapping und Beleuchtung weiterhin auf die Drahtgitterlinien angewendet werden, wenn sie aktiviert sind, was seltsam aussehen kann.
quelle
Von http://cone3d.gamedev.net/cgi-bin/index.pl?page=tutorials/ogladv/tut5
quelle
Unter der Annahme eines vorwärtskompatiblen Kontexts in OpenGL 3 und
glPolygonMode
höher können Sie entweder wie zuvor erwähnt verwenden. Beachten Sie jedoch, dass Linien mit einer Dicke von mehr als 1 Pixel jetzt veraltet sind. Während Sie also Dreiecke als Drahtrahmen zeichnen können, müssen sie sehr dünn sein. In OpenGL ES können SieGL_LINES
mit derselben Einschränkung verwenden.In OpenGL ist es möglich, Geometrie-Shader zu verwenden, um eingehende Dreiecke aufzunehmen, zu zerlegen und als Quads (wirklich Dreieckspaare) zur Rasterung zu senden, die dicke Linien emulieren. Eigentlich ziemlich einfach, außer dass Geometrie-Shader für schlechte Leistungsskalierung berüchtigt sind.
Stattdessen können Sie Fragment Shader verwenden, was auch in OpenGL ES funktioniert . Denken Sie daran, eine Textur eines Drahtrahmen-Dreiecks auf das Dreieck anzuwenden. Außer dass keine Textur benötigt wird, kann sie prozedural generiert werden. Aber genug geredet, lasst uns codieren. Fragment Shader:
Und Vertex Shader:
Hier sind die Schwerpunktkoordinaten einfach
(1, 0, 0)
,(0, 1, 0)
und(0, 0, 1)
für die drei Dreiecksspitzen (die Reihenfolge spielt keine Rolle, die in Dreiecksstreifen möglicherweise einfacher macht Verpackung).Der offensichtliche Nachteil dieses Ansatzes besteht darin, dass einige Texturkoordinaten verbraucht werden und Sie Ihr Scheitelpunktarray ändern müssen. Könnte mit einem sehr einfachen Geometrie-Shader gelöst werden, aber ich würde immer noch vermuten, dass er langsamer ist, als nur die GPU mit mehr Daten zu versorgen.
quelle
Wenn Sie die feste Pipeline (OpenGL <3.3) oder das Kompatibilitätsprofil verwenden, das Sie verwenden können
In diesem Fall können Sie die Linienbreite ändern, indem Sie glLineWidth aufrufen
Andernfalls müssen Sie den Polygonmodus in Ihrer Zeichenmethode (glDrawElements, glDrawArrays usw.) ändern, und es kann zu groben Ergebnissen kommen, da Ihre Scheitelpunktdaten für Dreiecke gelten und Sie Linien ausgeben. Für beste Ergebnisse sollten Sie einen Geometrie-Shader verwenden oder neue Daten für das Drahtmodell erstellen.
quelle
Am einfachsten ist es, die Grundelemente als zu zeichnen
GL_LINE_STRIP
.quelle
In Modern OpenGL (OpenGL 3.2 und höher) können Sie hierfür einen Geometry Shader verwenden:
Hinweise:
layout (line_strip, max_vertices=3) out;
zulayout (points, max_vertices=3) out;
quelle
Sie können Glut-Bibliotheken wie folgt verwenden:
für eine Kugel:
für einen Zylinder:
für einen Würfel:
quelle
Eine gute und einfache Möglichkeit zum Zeichnen von Anti-Alias-Linien auf einem nicht-Anti-Alias-Rendering-Ziel besteht darin, Rechtecke mit einer Breite von 4 Pixel und einer 1x4-Textur mit Alphakanalwerten von {0., 1., 1., 0.} Zu zeichnen. und verwenden Sie die lineare Filterung mit ausgeschaltetem Mip-Mapping. Dadurch werden die Linien 2 Pixel dick, Sie können jedoch die Textur für verschiedene Dicken ändern. Dies ist schneller und einfacher als barymetrische Berechnungen.
quelle
Verwenden Sie diese Funktion: void glPolygonMode (GLenum face, GLenum mode);
face: Gibt die Polygone an, für die der Modus gilt. kann GL_FRONT für die Vorderseite des Polygons und GL_BACK für seinen Rücken und GL_FRONT_AND_BACK für beide sein.
Modus: Drei Modi sind definiert und können im Modus angegeben werden:
GL_POINT: Polygonscheitelpunkte, die als Beginn einer Grenzkante markiert sind, werden als Punkte gezeichnet.
GL_LINE: Grenzkanten des Polygons werden als Liniensegmente gezeichnet. (dein Ziel)
GL_FILL: Das Innere des Polygons ist gefüllt.
PS: glPolygonMode steuert die Interpretation von Polygonen für die Rasterung in der Grafikpipeline.
Weitere Informationen finden Sie auf den OpenGL-Referenzseiten in der khronos-Gruppe: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonMode.xhtml
quelle
Wenn es sich um OpenGL ES 2.0 handelt , können Sie eine der Konstanten für den Zeichenmodus auswählen
GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES,
Linien ziehen,GL_POINTS
(wenn Sie nur Eckpunkte zeichnen müssen) oderGL_TRIANGLE_STRIP
,GL_TRIANGLE_FAN
UndGL_TRIANGLES
ausgefüllte Dreiecke zeichnenals erstes Argument an Ihre
oder
glDrawArrays(GLenum mode, GLint first, GLsizei count)
Anrufe.quelle