Wie rendern Sie Grundelemente in OpenGL als Drahtmodelle?

220

Wie rendern Sie Grundelemente in OpenGL als Drahtmodelle?


quelle
2
Seien Sie genauer auf die OpenGL-Version, die Sie verwenden.
Vertexwahn
Mit ModernGL können Sie einfach das Wireframe- Attribut der Context- Klasse verwenden
Szabolcs Dombi
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.


quelle
2
Ich mag dich. Noch 4.
Jo So
37

Von http://cone3d.gamedev.net/cgi-bin/index.pl?page=tutorials/ogladv/tut5

// Turn on wireframe mode
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);

// Draw the box
DrawBox();

// Turn off wireframe mode
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);
John Millikin
quelle
75
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 lines

void main()
{
    float f_closest_edge = min(v_barycentric.x,
        min(v_barycentric.y, v_barycentric.z)); // see to which edge this pixel is the closest
    float 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 matrix

void 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.

das Schwein
quelle
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 ...
user1167662
2
Natürlich tut es das. Sie können unter stackoverflow.com/questions/7361582/… auf die Implementierung derselben Idee durch eine andere Person verweisen .
das Schwein
1
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.

Zaphyk
quelle
3

Am einfachsten ist es, die Grundelemente als zu zeichnen GL_LINE_STRIP.

glBegin(GL_LINE_STRIP);
/* Draw vertices here */
glEnd();
Hochester
quelle
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:

LMD
quelle
1

Sie können Glut-Bibliotheken wie folgt verwenden:

  1. für eine Kugel:

    glutWireSphere(radius,20,20);
    
  2. für einen Zylinder:

    GLUquadric *quadratic = gluNewQuadric();
    gluQuadricDrawStyle(quadratic,GLU_LINE);
    gluCylinder(quadratic,1,1,1,12,1);
    
  3. für einen Würfel:

    glutWireCube(1.5);
    
H. Mohcen
quelle
0

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.

Peter Soltesz
quelle
0

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

omar ghannou
quelle
-1

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) oder

GL_TRIANGLE_STRIP, GL_TRIANGLE_FANUnd GL_TRIANGLESausgefüllte Dreiecke zeichnen

als erstes Argument an Ihre

glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)

oder

glDrawArrays(GLenum mode, GLint first, GLsizei count) Anrufe.

Sieger
quelle